✨ 运单结束后拒绝司机打卡

已完成/已取消的运单不再接受在途与节点打卡,卡片仍下发但不可提交。
This commit is contained in:
2026-10-20 14:37:12 +08:00
parent 02d75e7e95
commit aa0226e77b
3 changed files with 110 additions and 0 deletions
@@ -407,6 +407,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
// 在途打卡单独保留原取单判据,不排除已拒单(见 scopedQuery 的重载说明)
Waybill waybill = loadDriverWaybill(dto.getWaybillId(), true);
waybill = normalizeAcceptStatus(waybill);
assertPunchNotEnded(waybill.getBusinessStatus());
String processJson = resolveProcessJson(waybill);
Date lastPunchAt = findLastPunchTime(waybill.getId());
@@ -456,6 +457,7 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
Driver driver = requireCurrentDriver();
Waybill waybill = loadDriverWaybill(dto.getWaybillId());
waybill = normalizeAcceptStatus(waybill);
assertPunchNotEnded(waybill.getBusinessStatus());
String processJson = resolveProcessJson(waybill);
Map<String, Object> nodeCfg = findPunchNodeConfig(processJson, nodeCode);
@@ -1318,6 +1320,19 @@ public class DriverWaybillServiceImpl implements IDriverWaybillService {
.orElse(null);
}
/**
* 断言运单未结束。
* <p>
* 运单已完成/已取消后不再接受司机打卡:在途与节点都拦,且先于其它门禁。
* 结束不可逆,没有解除途径——处理完异常、等到第二天都还是打不了。
*/
private void assertPunchNotEnded(String businessStatus) {
String reason = WaybillProcessSupport.punchEndedReason(businessStatus);
if (reason != null) {
throw new ServiceException(reason);
}
}
/**
* 断言指定节点未被异常门禁阻断。
* <p>
@@ -133,6 +133,31 @@ public final class WaybillProcessSupport {
return ACCEPT_REJECTED.equalsIgnoreCase(stringVal(driverAcceptStatus));
}
/**
* 运单已结束:已完成或已取消。此后不再接受司机打卡。
* <p>
* 只认这两个状态,大小写不敏感。草稿、待执行、待调度、调度中的运单司机仍要能打卡,
* 所以不能按 {@link #isTerminalBusinessStatus} 的「终态或调度中间态」口径判定。
*/
public static boolean isPunchEnded(String businessStatus) {
String status = stringVal(businessStatus);
return "completed".equalsIgnoreCase(status) || "cancelled".equalsIgnoreCase(status);
}
/**
* 结束态下的打卡拒绝文案;非结束态返回 null。
*/
public static String punchEndedReason(String businessStatus) {
String status = stringVal(businessStatus);
if ("completed".equalsIgnoreCase(status)) {
return "运单已完成";
}
if ("cancelled".equalsIgnoreCase(status)) {
return "运单已取消";
}
return null;
}
public static boolean isTerminalBusinessStatus(String businessStatus) {
return "draft".equals(businessStatus)
|| "completed".equals(businessStatus)
@@ -198,6 +223,10 @@ public final class WaybillProcessSupport {
int frequencyDays = parsePositiveInt(transit.get("frequencyDays"), 1);
String timeStart = normalizeHm(stringVal(transit.get("timeStart")), "00:00");
String timeEnd = normalizeHm(stringVal(transit.get("timeEnd")), "23:59");
// 结束不可逆,没有解除途径:卡片仍下发,但不可提交,也不算今日待打
if (isPunchEnded(businessStatus)) {
return new TransitCheckinDecision(false, true, false, false, frequencyDays, timeStart, timeEnd);
}
// punch=是即展示卡片;非进行中仅不可作为「今日待打」
if (!STATUS_RUNNING.equals(businessStatus)) {
return new TransitCheckinDecision(true, true, false, false, frequencyDays, timeStart, timeEnd);