🐛 合并 websoft/dev:改路线重推站名并回退进行中运单配载准入
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+4
@@ -863,6 +863,10 @@ public class ExceptionDisposalServiceImpl
|
||||
if (Func.isNotBlank(plan.routeJson())) {
|
||||
waybill.setRouteJson(plan.routeJson());
|
||||
}
|
||||
waybill.setDepartureName(TransportBusinessSupport.syncRegionName(
|
||||
waybill.getDepartureName(), waybill.getDepartureAddress(), plan.departureAddress()));
|
||||
waybill.setArrivalName(TransportBusinessSupport.syncRegionName(
|
||||
waybill.getArrivalName(), waybill.getArrivalAddress(), plan.arrivalAddress()));
|
||||
waybill.setDepartureAddress(plan.departureAddress());
|
||||
waybill.setArrivalAddress(plan.arrivalAddress());
|
||||
waybill.setTaskInfoJson(plan.taskInfoJson());
|
||||
|
||||
+2
-2
@@ -884,8 +884,8 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
|
||||
String prefix = "运单" + waybill.getWaybillNo();
|
||||
return prefix + switch (reason) {
|
||||
case NOT_ROAD -> "运输方式不是公路,不可配载";
|
||||
case NOT_LOADABLE_STATUS -> "当前状态不是待执行或进行中,不可配载";
|
||||
case ON_OTHER_MANIFEST -> "已关联其他有效配载单";
|
||||
case NOT_PENDING -> "当前状态不是待执行,不可配载";
|
||||
case ON_OTHER_MANIFEST -> "已关联其他配载单";
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -1510,13 +1510,23 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
|
||||
if ("completed".equals(oldRecord.getBusinessStatus()) || "cancelled".equals(oldRecord.getBusinessStatus())) {
|
||||
throw new ServiceException("当前运单状态不允许变更运输路线");
|
||||
}
|
||||
String previousDepartureAddress = oldRecord.getDepartureAddress();
|
||||
String previousArrivalAddress = oldRecord.getArrivalAddress();
|
||||
oldRecord.setRouteJson(TransportBusinessSupport.trimToNull(waybill.getRouteJson()));
|
||||
oldRecord.setDepartureAddress(TransportBusinessSupport.trimToNull(waybill.getDepartureAddress()));
|
||||
oldRecord.setArrivalAddress(TransportBusinessSupport.trimToNull(waybill.getArrivalAddress()));
|
||||
oldRecord.setDepartureName(TransportBusinessSupport.syncRegionName(
|
||||
oldRecord.getDepartureName(), previousDepartureAddress, oldRecord.getDepartureAddress()));
|
||||
oldRecord.setArrivalName(TransportBusinessSupport.syncRegionName(
|
||||
oldRecord.getArrivalName(), previousArrivalAddress, oldRecord.getArrivalAddress()));
|
||||
oldRecord.setTaskInfoJson(TransportBusinessSupport.trimToNull(waybill.getTaskInfoJson()));
|
||||
TransportBusinessSupport.validateLength(oldRecord.getRouteJson(), 8000, "路线信息不能超过8000字");
|
||||
TransportBusinessSupport.validateLength(oldRecord.getDepartureAddress(), 255, "发货地址不能超过255字");
|
||||
TransportBusinessSupport.validateLength(oldRecord.getArrivalAddress(), 255, "收货地址不能超过255字");
|
||||
TransportBusinessSupport.validateLength(oldRecord.getDepartureName(),
|
||||
TransportBusinessSupport.REGION_NAME_MAX_LENGTH, "发货地不能超过100字");
|
||||
TransportBusinessSupport.validateLength(oldRecord.getArrivalName(),
|
||||
TransportBusinessSupport.REGION_NAME_MAX_LENGTH, "收货地不能超过100字");
|
||||
TransportBusinessSupport.validateLength(oldRecord.getTaskInfoJson(), 8000, "任务信息不能超过8000字");
|
||||
return updateById(oldRecord);
|
||||
}
|
||||
|
||||
+10
-13
@@ -29,7 +29,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 可配载准入判据:公路 + 待执行/进行中 + 未关联其它配载单。
|
||||
* 可配载准入判据:公路 + 待执行 + 未关联其它配载单。
|
||||
* <p>
|
||||
* 接单状态不进判据:拒单票照样可配载。配载提交会把它的接单事实清成待接单,
|
||||
* 否则新司机看不到这张票——司机端入口一律排除已拒绝的运单。
|
||||
@@ -38,11 +38,8 @@ import java.util.Locale;
|
||||
*/
|
||||
public final class LoadableAdmissionSupport {
|
||||
|
||||
/** 可配载业务状态:待执行、进行中;已完成、已取消、草稿与调度中间态一律不可配载 */
|
||||
public static final List<String> LOADABLE_BUSINESS_STATUSES = List.of(
|
||||
WaybillProcessSupport.STATUS_PENDING,
|
||||
WaybillProcessSupport.STATUS_RUNNING
|
||||
);
|
||||
/** 可配载只放行待执行:已完成、已取消、草稿与调度中间态一律不可配载 */
|
||||
public static final String LOADABLE_BUSINESS_STATUS = WaybillProcessSupport.STATUS_PENDING;
|
||||
|
||||
/**
|
||||
* 公路运输方式的同义写法,按「包含」比对,与前端运单管理页的识别口径一致。
|
||||
@@ -59,7 +56,7 @@ public final class LoadableAdmissionSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 不可配载的原因,按判定顺序排列:公路 → 待执行/进行中 → 未关联其它配载单。
|
||||
* 不可配载的原因,按判定顺序排列:公路 → 待执行 → 未关联其它配载单。
|
||||
* <p>
|
||||
* 判据只产出原因,中文文案由调用方映射——面向用户的措辞不进这一层。
|
||||
*/
|
||||
@@ -68,8 +65,8 @@ public final class LoadableAdmissionSupport {
|
||||
/** 运输方式不是公路 */
|
||||
NOT_ROAD,
|
||||
|
||||
/** 业务状态不是待执行或进行中 */
|
||||
NOT_LOADABLE_STATUS,
|
||||
/** 业务状态不是待执行 */
|
||||
NOT_PENDING,
|
||||
|
||||
/** 已关联其它配载单 */
|
||||
ON_OTHER_MANIFEST
|
||||
@@ -122,8 +119,8 @@ public final class LoadableAdmissionSupport {
|
||||
if (waybill == null || !isRoadTransport(waybill.getTransportType())) {
|
||||
return UnloadableReason.NOT_ROAD;
|
||||
}
|
||||
if (!LOADABLE_BUSINESS_STATUSES.contains(text(waybill.getBusinessStatus()))) {
|
||||
return UnloadableReason.NOT_LOADABLE_STATUS;
|
||||
if (!LOADABLE_BUSINESS_STATUS.equals(text(waybill.getBusinessStatus()))) {
|
||||
return UnloadableReason.NOT_PENDING;
|
||||
}
|
||||
String loadingNo = text(waybill.getLoadingNo());
|
||||
if (loadingNo.isEmpty() || loadingNo.equals(text(ownLoadingNo))) {
|
||||
@@ -151,13 +148,13 @@ public final class LoadableAdmissionSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 把整条可配载判据加到运单查询上:公路 + 待执行/进行中 + 未配载。
|
||||
* 把整条可配载判据加到运单查询上:公路 + 待执行 + 未配载。
|
||||
*
|
||||
* @param wrapper 运单列表查询条件
|
||||
*/
|
||||
public static void applyLoadableConditions(LambdaQueryWrapper<Waybill> wrapper) {
|
||||
applyRoadTransportCondition(wrapper);
|
||||
wrapper.in(Waybill::getBusinessStatus, LOADABLE_BUSINESS_STATUSES);
|
||||
wrapper.eq(Waybill::getBusinessStatus, LOADABLE_BUSINESS_STATUS);
|
||||
wrapper.and(nested -> nested.isNull(Waybill::getLoadingNo).or().eq(Waybill::getLoadingNo, ""));
|
||||
}
|
||||
|
||||
|
||||
+71
@@ -37,6 +37,7 @@ import java.time.LocalDate;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -50,8 +51,18 @@ public final class TransportBusinessSupport {
|
||||
public static final String DATA_SOURCE_MANUAL = "手工创建";
|
||||
public static final String DATA_SOURCE_PLAN_DISPATCH = "计划调度";
|
||||
public static final String DATA_SOURCE_EXTERNAL = "外部系统";
|
||||
/** 站点名(省+市+区县)列宽:blade_waybill.departure_name / arrival_name 为 varchar(100) */
|
||||
public static final int REGION_NAME_MAX_LENGTH = 100;
|
||||
|
||||
private static final Pattern PHONE_PATTERN = Pattern.compile("^(1\\d{10}|0\\d{2,3}-?\\d{7,8})$");
|
||||
/** 省级前缀:主体不含市/区/县,避免把「北京市朝阳区某省道」当省级 */
|
||||
private static final Pattern PROVINCE_PATTERN = Pattern.compile("^[^市区县]{2,10}?(?:省|特别行政区|自治区)");
|
||||
/** 市级:地级市名 2~4 字,「市场」的市不算(地址里常见「农贸市场」「超市」) */
|
||||
private static final Pattern CITY_PATTERN = Pattern.compile("^[^区县旗市]{2,4}?市(?!场)");
|
||||
/** 市级:自治州/地区/盟 的名字可以更长 */
|
||||
private static final Pattern PREFECTURE_PATTERN = Pattern.compile("^[^区县旗市]{2,10}?(?:自治州|地区|盟)");
|
||||
/** 区县:县级市不单独进站名,只取到地级市 */
|
||||
private static final Pattern DISTRICT_PATTERN = Pattern.compile("^[^市县]{2,10}?(?:区|县|旗)");
|
||||
private static final BigDecimal MIN_LONGITUDE = new BigDecimal("-180");
|
||||
private static final BigDecimal MAX_LONGITUDE = new BigDecimal("180");
|
||||
private static final BigDecimal MIN_LATITUDE = new BigDecimal("-90");
|
||||
@@ -426,4 +437,64 @@ public final class TransportBusinessSupport {
|
||||
return mileage == null ? null : mileage.stripTrailingZeros().toPlainString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按地址推导站名:省 + 市 + 区/县/旗。
|
||||
* <p>
|
||||
* 库里的站名就是这个口径(如「内蒙古自治区鄂尔多斯市鄂托克旗」「北京市朝阳区」),
|
||||
* 只写地址不写站名会让司机端继续显示旧城市。地址里的「/」是分隔写法,推导时去掉;
|
||||
* 认不出城市的退回整段地址,不拼半截区县名。
|
||||
*/
|
||||
public static String deriveRegionName(String address) {
|
||||
String value = trimToNull(address);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String rest = value.replace("/", "");
|
||||
String province = matchPrefix(rest, PROVINCE_PATTERN);
|
||||
if (!province.isEmpty()) {
|
||||
rest = rest.substring(province.length());
|
||||
}
|
||||
String city = matchPrefix(rest, CITY_PATTERN);
|
||||
if (city.isEmpty()) {
|
||||
city = matchPrefix(rest, PREFECTURE_PATTERN);
|
||||
}
|
||||
if (city.isEmpty()) {
|
||||
return truncateRegionName(value);
|
||||
}
|
||||
StringBuilder name = new StringBuilder(province).append(city);
|
||||
String district = matchPrefix(rest.substring(city.length()), DISTRICT_PATTERN);
|
||||
if (!district.isEmpty()) {
|
||||
name.append(district);
|
||||
}
|
||||
return truncateRegionName(name.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 地址变了才按新地址重推站名,地址没动保留库里原有的站名。
|
||||
*
|
||||
* @param currentName 库里当前的站名
|
||||
* @param previousAddress 改动前的地址
|
||||
* @param nextAddress 改动后的地址
|
||||
* @return 新地址对应的站名,地址被清空时返回 null
|
||||
*/
|
||||
public static String syncRegionName(String currentName, String previousAddress, String nextAddress) {
|
||||
String next = trimToNull(nextAddress);
|
||||
if (next == null) {
|
||||
return null;
|
||||
}
|
||||
if (Objects.equals(trimToNull(previousAddress), next)) {
|
||||
return trimToNull(currentName);
|
||||
}
|
||||
return deriveRegionName(next);
|
||||
}
|
||||
|
||||
private static String matchPrefix(String text, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
return matcher.find() ? matcher.group() : "";
|
||||
}
|
||||
|
||||
private static String truncateRegionName(String value) {
|
||||
return value.length() > REGION_NAME_MAX_LENGTH ? value.substring(0, REGION_NAME_MAX_LENGTH) : value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user