Merge remote-tracking branch 'websoft/dev'
This commit is contained in:
+4
-1
@@ -90,9 +90,12 @@ public class AdminWaybillDetailVO implements Serializable {
|
||||
@Schema(description = "运输方式字典值:road 等")
|
||||
private String transportMode;
|
||||
|
||||
@Schema(description = "运输组织:common普通 / load配载")
|
||||
@Schema(description = "运输类型:common普通运输 / load配载运输")
|
||||
private String transportOrgType;
|
||||
|
||||
@Schema(description = "是否挂多联总单:为真表示这趟含多式联运,与配载运输可叠加(不与 transportOrgType 互斥)")
|
||||
private Boolean multimodal;
|
||||
|
||||
@Schema(description = "计划发货时间")
|
||||
private String planShipTime;
|
||||
|
||||
|
||||
+5
-3
@@ -11,7 +11,6 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -103,8 +102,11 @@ public class DriverPunchNodeVO implements Serializable {
|
||||
@Schema(description = "本节点是否需要采集里程(末位可打卡节点且计费规则含里程)")
|
||||
private Boolean needMileage;
|
||||
|
||||
@Schema(description = "运单里程(公里),needMileage 为真时用于回显")
|
||||
private BigDecimal mileage;
|
||||
/**
|
||||
* 里程只有正整数口径(ADR-0023 决策 6),下发的是去尾随零的文本,如 "200" 而非 "200.00"。
|
||||
*/
|
||||
@Schema(description = "运单里程(公里,正整数文本),needMileage 为真时用于回显")
|
||||
private String mileage;
|
||||
|
||||
@Schema(description = "已上传凭证图(已打卡回显)")
|
||||
private List<DriverPunchPhotoVO> photos = new ArrayList<>();
|
||||
|
||||
+4
-1
@@ -156,9 +156,12 @@ public class DriverWaybillCardVO implements Serializable {
|
||||
@Schema(description = "运输方式文案:公路运输等")
|
||||
private String transportType;
|
||||
|
||||
@Schema(description = "运输组织:common普通 / load配载")
|
||||
@Schema(description = "运输类型:common普通运输 / load配载运输")
|
||||
private String transportOrgType;
|
||||
|
||||
@Schema(description = "是否挂多联总单:为真表示这趟含多式联运,与配载运输可叠加(不与 transportOrgType 互斥)")
|
||||
private Boolean multimodal;
|
||||
|
||||
/* ===== 运次(一趟车)字段:运次接口返回,旧运单接口不填 ===== */
|
||||
|
||||
@Schema(description = "运次主键:配载单主键或运单主键,按字符串下发(19 位雪花号按数字下发会被前端取整)")
|
||||
|
||||
+4
-1
@@ -54,9 +54,12 @@ public class TripVO implements Serializable {
|
||||
@Schema(description = "配载单号,未配载为空")
|
||||
private String loadingNo;
|
||||
|
||||
@Schema(description = "运输组织类型:load 公路配载 / common 普通运输")
|
||||
@Schema(description = "运输类型:load 配载运输 / common 普通运输")
|
||||
private String transportOrgType;
|
||||
|
||||
@Schema(description = "是否挂多联总单:为真表示这趟含多式联运,与配载运输可叠加(不与 transportOrgType 互斥)")
|
||||
private Boolean multimodal;
|
||||
|
||||
@Schema(description = "状态:0待接单/1运输中/2已完成/3已取消,子单集合为空时为空")
|
||||
private Integer status;
|
||||
|
||||
|
||||
+5
-3
@@ -9,7 +9,6 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -62,8 +61,11 @@ public class WaybillPunchRecordItemVO implements Serializable {
|
||||
@Schema(description = "本条是否需要采集里程(末位打卡节点且计费规则含里程)")
|
||||
private Boolean needMileage;
|
||||
|
||||
@Schema(description = "运单里程(公里),needMileage 为真时用于回显")
|
||||
private BigDecimal mileage;
|
||||
/**
|
||||
* 里程只有正整数口径(ADR-0023 决策 6),下发的是去尾随零的文本,如 "200" 而非 "200.00"。
|
||||
*/
|
||||
@Schema(description = "运单里程(公里,正整数文本),needMileage 为真时用于回显")
|
||||
private String mileage;
|
||||
|
||||
@Schema(description = "里程是否已冻结(运单已生成结算单,只能看不能改)")
|
||||
private Boolean mileageLocked;
|
||||
|
||||
+3
-1
@@ -1055,6 +1055,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
card.setCargos(withDetail ? cargoLines(cargos) : null);
|
||||
card.setTransportType(toTransportTypeLabel(waybill.getTransportType()));
|
||||
card.setTransportOrgType(Func.isNotBlank(waybill.getLoadingNo()) ? TRANSPORT_LOAD : TRANSPORT_COMMON);
|
||||
card.setMultimodal(Func.isNotBlank(waybill.getMasterNo()));
|
||||
card.setPlanShipTime(formatLocalDateYmd(waybill.getEstimatedStartTime()));
|
||||
card.setPlanFinishTime(formatLocalDateYmd(waybill.getEstimatedEndTime()));
|
||||
card.setRemark(Func.toStr(waybill.getRemark(), ""));
|
||||
@@ -1141,6 +1142,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
card.setRequireAccept(trip.getRequireAccept());
|
||||
card.setAcceptStatus(trip.getAcceptStatus());
|
||||
card.setTransportOrgType(trip.getTransportOrgType());
|
||||
card.setMultimodal(trip.getMultimodal());
|
||||
card.setTransportType(toTransportTypeLabel(trip.getTransportType()));
|
||||
card.setDriverName(Func.toStr(trip.getDriverName(), ""));
|
||||
card.setDriverPhone(Func.toStr(trip.getDriverPhone(), ""));
|
||||
@@ -1649,7 +1651,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
|
||||
// 里程同样只在末位卡采集:末位判定与上面同一个变量,避免两处各算一次走偏。
|
||||
if (lastPunchNode && lastNodeNeedsMileage) {
|
||||
vo.setNeedMileage(true);
|
||||
vo.setMileage(waybill.getMileage());
|
||||
vo.setMileage(TransportBusinessSupport.mileageText(waybill.getMileage()));
|
||||
}
|
||||
if (done) {
|
||||
if (punched.getPunchTime() != null) {
|
||||
|
||||
+4
@@ -445,6 +445,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
detail.setTransportMode(Func.toStr(trip.getTransportType(), ""));
|
||||
detail.setTransportType(toTransportTypeLabel(Func.toStr(trip.getTransportType(), "")));
|
||||
detail.setTransportOrgType(Func.isEmpty(trip.getLoadingNo()) ? TRANSPORT_COMMON : TRANSPORT_LOAD);
|
||||
detail.setMultimodal(Boolean.TRUE.equals(trip.getMultimodal()));
|
||||
detail.setTripId(trip.getId());
|
||||
detail.setLoadingNo(Func.toStr(trip.getLoadingNo(), ""));
|
||||
detail.setTripNo(Func.toStr(trip.getTripNo(), ""));
|
||||
@@ -504,6 +505,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
detail.setLoadingNo(loading.getLoadingNo());
|
||||
detail.setTripNo(loading.getLoadingNo());
|
||||
detail.setTransportOrgType(TRANSPORT_LOAD);
|
||||
detail.setMultimodal(children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo())));
|
||||
detail.setViaName(TripStationAssembler.transitName(stations));
|
||||
detail.setStationCount(stations.size());
|
||||
detail.setStations(stations);
|
||||
@@ -538,6 +540,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
detail.setTransportMode(Func.toStr(loading.getTransportType(), ""));
|
||||
detail.setTransportType(toTransportTypeLabel(Func.toStr(loading.getTransportType(), "")));
|
||||
detail.setTransportOrgType(TRANSPORT_LOAD);
|
||||
detail.setMultimodal(children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo())));
|
||||
detail.setTripId(String.valueOf(loading.getId()));
|
||||
detail.setLoadingNo(loading.getLoadingNo());
|
||||
detail.setTripNo(loading.getLoadingNo());
|
||||
@@ -777,6 +780,7 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
|
||||
detail.setTransportMode(mode);
|
||||
detail.setTransportType(toTransportTypeLabel(mode));
|
||||
detail.setTransportOrgType(Func.isNotBlank(waybill.getLoadingNo()) ? TRANSPORT_LOAD : TRANSPORT_COMMON);
|
||||
detail.setMultimodal(Func.isNotBlank(waybill.getMasterNo()));
|
||||
|
||||
detail.setFromName(formatPlaceName(waybill.getDepartureName(), mode));
|
||||
detail.setToName(formatPlaceName(waybill.getArrivalName(), mode));
|
||||
|
||||
+27
-12
@@ -79,9 +79,10 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
private static final int DEFAULT_PAGE_SIZE = 10;
|
||||
private static final int MAX_PAGE_SIZE = 50;
|
||||
|
||||
/** 运输组织类型:有配载单为公路配载,否则普通运输 */
|
||||
/** 运输类型:有配载单为配载运输,挂多联总单为多式联运,两者都没有为普通运输 */
|
||||
private static final String TRANSPORT_LOAD = "load";
|
||||
private static final String TRANSPORT_COMMON = "common";
|
||||
private static final String TRANSPORT_MULTIMODAL = "multimodal";
|
||||
|
||||
/** 未配载运次的键前缀:与 TripAggregation.SQL_TRIP_KEY 的 W 前缀同一个口径 */
|
||||
private static final String LONE_KEY_PREFIX = "W";
|
||||
@@ -185,8 +186,8 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
/**
|
||||
* 全部可见运次:一次取回运单行后在服务层分组、分档、筛选并按排序键倒序
|
||||
* <p>
|
||||
* 分档用过程配置与接单态推导,于是 Tab 与卡片必然同档;行级筛选(组织类型 / 异常 / 创建时间)落在库层,
|
||||
* 命中的行同时决定这一趟车的子单集合与分档。
|
||||
* 分档用过程配置与接单态推导,于是 Tab 与卡片必然同档;异常与创建时间按整趟车的子单集合判,
|
||||
* 运输类型也在这里判——三者都不在库层筛行,否则一趟车会被劈成两半、三档数目加起来对不上全部。
|
||||
*/
|
||||
private List<TripRows> trips(TripQueryVO condition) {
|
||||
Map<String, List<Waybill>> grouped = new LinkedHashMap<>();
|
||||
@@ -202,7 +203,7 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
return;
|
||||
}
|
||||
List<Waybill> children = sortedChildren(rows);
|
||||
if (!inScope(children, condition)) {
|
||||
if (!matchesOrgType(children, condition.getTransportOrgType()) || !inScope(children, condition)) {
|
||||
return;
|
||||
}
|
||||
boolean requireAccept = TripAggregation.requiresAccept(children);
|
||||
@@ -244,6 +245,8 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
Waybill::getDepartureName, Waybill::getDepartureAddress, Waybill::getArrivalName,
|
||||
Waybill::getArrivalAddress, Waybill::getDriverName, Waybill::getDriverPhone, Waybill::getVehicleNo,
|
||||
Waybill::getCustomerName, Waybill::getTransportType, Waybill::getTaskRemark,
|
||||
// 运输类型的三态靠它派生,行级筛选也按它判,必须随行取回
|
||||
Waybill::getMasterNo,
|
||||
// 未配载运次没有配载单可依,计划时间要取运单自己的,故必须随行取回
|
||||
Waybill::getEstimatedStartTime, Waybill::getEstimatedEndTime, Waybill::getCreateTime)
|
||||
.in(Waybill::getBusinessStatus, TripAggregation.CHILD_STATUSES)
|
||||
@@ -252,7 +255,6 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
applyScope(wrapper, condition);
|
||||
applyDeptScope(wrapper, condition);
|
||||
applyProjectScope(wrapper, condition);
|
||||
applyOrgTypeFilter(wrapper, condition);
|
||||
applyKeyword(wrapper, condition.getKeyword());
|
||||
List<Waybill> rows = waybillService.list(wrapper);
|
||||
applyLiveProcessConfig(rows);
|
||||
@@ -285,15 +287,25 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 运输组织类型按子单行筛:它在同一趟车里必然是同一个值(配载的每张子单带同一个配载单号,
|
||||
* 未配载的每张自成一趟车),所以这一层不会把一趟车拆开。
|
||||
* 运输类型按整趟车判,三档互斥且覆盖全部运次:普通 = 不挂配载单也不挂总单,
|
||||
* 配载 = 挂配载单且整趟车没挂总单,多式联运 = 任一子单挂总单(不问有没有配载)。
|
||||
* <p>
|
||||
* 不能按子单行筛:一张配载单可以混装挂总单与不挂总单的运单,行级筛会让同一趟车同时落进
|
||||
* 配载与多式联运两档,而每档里只剩命中的那部分子单——卡片上的运单数、货物与重量都会缩水,
|
||||
* 三个档的数目加起来也对不上「全部」。判据只能落在取回后的整趟车集合上。
|
||||
*/
|
||||
private void applyOrgTypeFilter(LambdaQueryWrapper<Waybill> wrapper, TripQueryVO condition) {
|
||||
if (TRANSPORT_LOAD.equals(condition.getTransportOrgType())) {
|
||||
wrapper.apply("IFNULL(loading_no, '') <> ''");
|
||||
} else if (TRANSPORT_COMMON.equals(condition.getTransportOrgType())) {
|
||||
wrapper.apply("IFNULL(loading_no, '') = ''");
|
||||
private static boolean matchesOrgType(List<Waybill> children, String transportOrgType) {
|
||||
if (Func.isBlank(transportOrgType)) {
|
||||
return true;
|
||||
}
|
||||
boolean multimodal = children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo()));
|
||||
boolean loaded = children.stream().anyMatch(child -> Func.isNotBlank(child.getLoadingNo()));
|
||||
return switch (transportOrgType) {
|
||||
case TRANSPORT_MULTIMODAL -> multimodal;
|
||||
case TRANSPORT_LOAD -> loaded && !multimodal;
|
||||
case TRANSPORT_COMMON -> !loaded && !multimodal;
|
||||
default -> true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -530,6 +542,8 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
trip.setLoadingNo(loading.getLoadingNo());
|
||||
trip.setTripNo(loading.getLoadingNo());
|
||||
trip.setTransportOrgType(TRANSPORT_LOAD);
|
||||
// 多式联运与配载可叠加:任一子单挂总单即算这趟车含多式联运
|
||||
trip.setMultimodal(children.stream().anyMatch(child -> Func.isNotBlank(child.getMasterNo())));
|
||||
trip.setDriverName(Func.toStr(loading.getDriverName(), ""));
|
||||
trip.setDriverPhone(Func.toStr(loading.getDriverPhone(), ""));
|
||||
trip.setVehicleNo(Func.toStr(loading.getVehicleNo(), ""));
|
||||
@@ -562,6 +576,7 @@ public class TripQueryServiceImpl implements ITripQueryService {
|
||||
trip.setId(tripIdOf(waybill.getId()));
|
||||
trip.setTripNo(waybill.getWaybillNo());
|
||||
trip.setTransportOrgType(TRANSPORT_COMMON);
|
||||
trip.setMultimodal(Func.isNotBlank(waybill.getMasterNo()));
|
||||
trip.setDriverName(Func.toStr(waybill.getDriverName(), ""));
|
||||
trip.setDriverPhone(Func.toStr(waybill.getDriverPhone(), ""));
|
||||
trip.setVehicleNo(Func.toStr(waybill.getVehicleNo(), ""));
|
||||
|
||||
+1
-1
@@ -442,7 +442,7 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
item.setType(isTransit ? "enroute" : "node");
|
||||
if (lastNodeNeedsMileage && !isTransit && lastPunchKey.equals(nodeCode)) {
|
||||
item.setNeedMileage(true);
|
||||
item.setMileage(waybill.getMileage());
|
||||
item.setMileage(TransportBusinessSupport.mileageText(waybill.getMileage()));
|
||||
item.setMileageLocked(punchMileageLocked);
|
||||
}
|
||||
item.setExceptionFlag(false);
|
||||
|
||||
+9
@@ -282,4 +282,13 @@ public final class TransportBusinessSupport {
|
||||
return mileage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 里程回显文本:去掉列上 decimal(18,2) 带来的尾随零,使 "200.00" 下发为 "200"。
|
||||
* <p>
|
||||
* 客户端按正整数校验里程,回显成两位小数会被当成非法值拒掉——不清零就等于「原样回填不能提交」。
|
||||
*/
|
||||
public static String mileageText(BigDecimal mileage) {
|
||||
return mileage == null ? null : mileage.stripTrailingZeros().toPlainString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
@@ -149,6 +149,19 @@ class DriverTripCardTest {
|
||||
assertEquals("桂A32523", card.getVehicleNo());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("运次卡片带多式联运:与配载两个事实并存,不被合并成一个单选")
|
||||
void tripCardCarriesMultimodalFlag() {
|
||||
TripVO trip = loadingTrip();
|
||||
trip.setMultimodal(true);
|
||||
stubTripPage(1, trip);
|
||||
|
||||
DriverWaybillCardVO card = runAsDriver(() -> service.tripPage(1, 10, null, null)).getRecords().get(0);
|
||||
|
||||
assertEquals("load", card.getTransportOrgType());
|
||||
assertEquals(Boolean.TRUE, card.getMultimodal());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("运次卡片带唯一原始业务状态:子单都在待回单确认时下发 pending_return_confirm,数字态仍是 1")
|
||||
void tripCardCarriesUniqueChildBusinessStatus() {
|
||||
|
||||
+13
@@ -216,6 +216,19 @@ class ManageTripListDetailTest {
|
||||
assertEquals("2131150784070275011", second.getCargos().get(1).getWaybillId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("详情带多式联运:运次上派生的标志原样下发,与配载并存")
|
||||
void detailCarriesMultimodalFlag() {
|
||||
TripVO trip = trip();
|
||||
trip.setMultimodal(true);
|
||||
when(tripQueryService.detail(any())).thenReturn(trip);
|
||||
|
||||
AdminWaybillDetailVO detail = service.detail(String.valueOf(LOADING_ID));
|
||||
|
||||
assertEquals("load", detail.getTransportOrgType());
|
||||
assertEquals(Boolean.TRUE, detail.getMultimodal(), "运输类型两个事实都下发,文案由前端组合");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("取不到运次时按运单主键与配载单主键回落:整单被拒的配载单仍能打开并重新派单")
|
||||
void detailFallsBackWhenTripIsNotReachable() {
|
||||
|
||||
+121
-2
@@ -249,6 +249,35 @@ class TripQueryServiceImplTest {
|
||||
verify(waybillService, times(1)).list(anyWaybillWrapper());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("未配载但挂总单:含多式联运,组织类型仍是普通运输")
|
||||
void unloadedWaybillOnMasterOrderIsMultimodal() {
|
||||
Waybill row = waybill(WAYBILL_ID, "YD-20260920-0003", null, "running", null, at(1000L), ACCEPT_NO);
|
||||
row.setMasterNo("DL-20261001-0001");
|
||||
stubRows(row);
|
||||
|
||||
TripVO trip = service.page(TripQueryVO.forDriver(PHONE)).getRecords().get(0);
|
||||
|
||||
assertEquals(Boolean.TRUE, trip.getMultimodal(), "挂总单即含多式联运");
|
||||
assertEquals("common", trip.getTransportOrgType(), "运输类型是组织形态维,与多式联运各算一个值");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("配载运次混装总单运单:只要有一张挂总单,整趟车就含多式联运,且配载事实仍在")
|
||||
void loadingTripIsMultimodalWhenAnyChildIsOnMasterOrder() {
|
||||
Waybill onMasterOrder = waybill(2092186187239780353L, "YD-1", LOADING_NO, "running", null, at(2000L), ACCEPT_NO);
|
||||
onMasterOrder.setMasterNo("DL-20261001-0001");
|
||||
stubRows(
|
||||
onMasterOrder,
|
||||
waybill(2092186187470467073L, "YD-2", LOADING_NO, "running", null, at(1000L), ACCEPT_NO));
|
||||
when(loadingManageService.list(anyLoadingWrapper())).thenReturn(List.of(loading(PHONE)));
|
||||
|
||||
TripVO trip = service.page(TripQueryVO.forDriver(PHONE)).getRecords().get(0);
|
||||
|
||||
assertEquals("load", trip.getTransportOrgType());
|
||||
assertEquals(Boolean.TRUE, trip.getMultimodal(), "两个事实叠加,不做互斥单选");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("未配载运次的状态与接单需求来自段一取回的那张运单")
|
||||
void unloadedTripStateComesFromFetchedWaybill() {
|
||||
@@ -461,7 +490,7 @@ class TripQueryServiceImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("管理端筛选:组织类型按子单行筛(同一趟车里是同一个值),异常与创建时间不进 SQL")
|
||||
@DisplayName("管理端筛选:异常与创建时间不进 SQL,运输类型也不按子单行筛")
|
||||
void adminFiltersStayAtTripGranularity() {
|
||||
TripQueryVO query = TripQueryVO.forAdmin();
|
||||
query.setTransportOrgType("common");
|
||||
@@ -473,10 +502,52 @@ class TripQueryServiceImplTest {
|
||||
service.page(query);
|
||||
|
||||
String sql = capturedRowSql();
|
||||
assertTrue(sql.contains("IFNULL(loading_no, '') = ''"), "普通运输在库层按子单行筛:" + sql);
|
||||
assertFalse(sql.contains("id NOT IN ("), "异常要看整趟车,不能在库层缩小子单集合:" + sql);
|
||||
assertFalse(sql.contains("create_time"), "创建时间按运次排序键在服务层判:" + sql);
|
||||
assertFalse(sql.contains("blade_loading_manage"), "管理端不按司机收口:" + sql);
|
||||
assertFalse(sql.contains("IFNULL(loading_no, '') = ''"), "运输类型按整趟车判,行级筛会把叠加的运次劈成两半:" + sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("运输类型三档是整趟车的分区:互不重叠,合起来正好是全部运次")
|
||||
void orgTypeTabsPartitionTrips() {
|
||||
stubFourTrips();
|
||||
|
||||
Set<String> common = tripNos("common");
|
||||
Set<String> load = tripNos("load");
|
||||
Set<String> multimodal = tripNos("multimodal");
|
||||
Set<String> all = tripNos(null);
|
||||
|
||||
assertEquals(Set.of("YD-PT"), common, "两列都空的整张运单才是普通运输");
|
||||
assertEquals(Set.of("PZ-1"), load, "叠加配载与总单的那趟车只落多式联运档,不能两档都算");
|
||||
assertEquals(Set.of("YD-DS", "PZ-2"), multimodal, "任一子单挂总单即含水陆联运之外的多式联运");
|
||||
assertEquals(all, union(common, load, multimodal), "三档计数加起来必须等于全部,否则用户看到的数目对不上");
|
||||
assertEquals(4, all.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("按规定判:叠加的那趟车在多式联运档里保留整趟车的子单,不被子单行筛劈成一半")
|
||||
void multimodalTabKeepsWholesaleTrip() {
|
||||
stubFourTrips();
|
||||
|
||||
TripVO mixed = orgTypeTrips("multimodal").stream()
|
||||
.filter(trip -> "PZ-2".equals(trip.getTripNo()))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new AssertionError("叠加配载与总单的那趟车必须出现在多式联运档"));
|
||||
|
||||
assertEquals(2, mixed.getWaybillCount(), "两柱子单都要数进去,否则卡片上的运单数与列表总数对不上");
|
||||
assertEquals(Boolean.TRUE, mixed.getMultimodal());
|
||||
assertEquals("load", mixed.getTransportOrgType(), "组织形态仍是配载,多式联运是叠加出来的第二个事实");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("运输类型没给或不认识时不筛:四趟车一辆不少")
|
||||
void unknownOrgTypeKeepsEveryTrip() {
|
||||
stubFourTrips();
|
||||
|
||||
assertEquals(4, orgTypeTrips(null).size());
|
||||
assertEquals(4, orgTypeTrips("").size());
|
||||
assertEquals(4, orgTypeTrips("whatever").size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -621,6 +692,47 @@ class TripQueryServiceImplTest {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 四趟车:普通(两列都空)、配载(只挂配载单)、未配载但挂总单、配载与总单叠加。
|
||||
* 叠加那趟车混装一张挂总单的子单和一张不挂的,正是行级筛会劈开它的场景。
|
||||
*/
|
||||
private void stubFourTrips() {
|
||||
Waybill multimodalLone = waybill(3001L, "YD-DS", null, "running", null, at(3000L), ACCEPT_NO);
|
||||
multimodalLone.setMasterNo("DL-20261001-0001");
|
||||
Waybill mixedOnMaster = waybill(4001L, "YD-HH-1", "PZ-2", "running", null, at(4000L), ACCEPT_NO);
|
||||
mixedOnMaster.setMasterNo("DL-20261001-0002");
|
||||
stubRows(
|
||||
waybill(1001L, "YD-PT", null, "running", null, at(1000L), ACCEPT_NO),
|
||||
waybill(2001L, "YD-PZ-1", "PZ-1", "running", null, at(2000L), ACCEPT_NO),
|
||||
waybill(2002L, "YD-PZ-2", "PZ-1", "running", null, at(2001L), ACCEPT_NO),
|
||||
multimodalLone,
|
||||
mixedOnMaster,
|
||||
waybill(4002L, "YD-HH-2", "PZ-2", "running", null, at(4001L), ACCEPT_NO));
|
||||
when(loadingManageService.list(anyLoadingWrapper())).thenReturn(List.of(loading("PZ-1", 2000L), loading("PZ-2", 4000L)));
|
||||
}
|
||||
|
||||
private List<TripVO> orgTypeTrips(String orgType) {
|
||||
TripQueryVO query = TripQueryVO.forDriver(PHONE);
|
||||
query.setTransportOrgType(orgType);
|
||||
query.setCurrent(1);
|
||||
query.setSize(50);
|
||||
return service.page(query).getRecords();
|
||||
}
|
||||
|
||||
private Set<String> tripNos(String orgType) {
|
||||
return orgTypeTrips(orgType).stream().map(TripVO::getTripNo)
|
||||
.collect(java.util.stream.Collectors.toCollection(java.util.LinkedHashSet::new));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static Set<String> union(Set<String>... parts) {
|
||||
Set<String> union = new java.util.LinkedHashSet<>();
|
||||
for (Set<String> part : parts) {
|
||||
union.addAll(part);
|
||||
}
|
||||
return union;
|
||||
}
|
||||
|
||||
private void stubOneLoadedTrip() {
|
||||
stubRows(
|
||||
waybill(2092186187239780353L, "YD-20260825-0006", LOADING_NO, "running", null, at(2000L), ACCEPT_YES),
|
||||
@@ -649,6 +761,13 @@ class TripQueryServiceImplTest {
|
||||
return query;
|
||||
}
|
||||
|
||||
private LoadingManage loading(String loadingNo, Long loadingId) {
|
||||
LoadingManage loading = loading(PHONE);
|
||||
loading.setId(loadingId);
|
||||
loading.setLoadingNo(loadingNo);
|
||||
return loading;
|
||||
}
|
||||
|
||||
private LoadingManage loading(String driverPhone) {
|
||||
LoadingManage loading = new LoadingManage();
|
||||
loading.setId(LOADING_ID);
|
||||
|
||||
+1
-1
@@ -211,7 +211,7 @@ class WaybillPunchRecordListTest {
|
||||
// 接单不参与司机打卡序列,末位是装货
|
||||
assertFalse(Boolean.TRUE.equals(accept.getNeedMileage()));
|
||||
assertTrue(Boolean.TRUE.equals(load.getNeedMileage()));
|
||||
assertEquals(0, new BigDecimal("128").compareTo(load.getMileage()));
|
||||
assertEquals("128", load.getMileage());
|
||||
assertFalse(Boolean.TRUE.equals(load.getMileageLocked()));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user