🔀 合并待回单确认状态常量与门禁

This commit is contained in:
2026-10-22 13:38:08 +08:00
2 changed files with 52 additions and 9 deletions
@@ -49,6 +49,8 @@ public final class WaybillProcessSupport {
public static final String STATUS_PENDING = "pending";
public static final String STATUS_RUNNING = "running";
/** 司机已打完末位卡、回单需业务员确认,尚未生成应收应付 */
public static final String STATUS_PENDING_RETURN_CONFIRM = "pending_return_confirm";
public static final String ACCEPT_PENDING = "pending";
public static final String ACCEPT_ACCEPTED = "accepted";
public static final String ACCEPT_REJECTED = "rejected";
@@ -134,14 +136,16 @@ public final class WaybillProcessSupport {
}
/**
* 运单已结束:已完成或已取消。此后不再接受司机打卡。
* 运单已结束:已完成、已取消,或已打完末位卡停在待回单确认。此后不再接受司机打卡。
* <p>
* 只认这两个状态,大小写不敏感。草稿、待执行、待调度、调度中的运单司机仍要能打卡,
* 只认这三个状态,大小写不敏感。草稿、待执行、待调度、调度中的运单司机仍要能打卡,
* 所以不能按 {@link #isTerminalBusinessStatus} 的「终态或调度中间态」口径判定。
*/
public static boolean isPunchEnded(String businessStatus) {
String status = stringVal(businessStatus);
return "completed".equalsIgnoreCase(status) || "cancelled".equalsIgnoreCase(status);
return "completed".equalsIgnoreCase(status)
|| "cancelled".equalsIgnoreCase(status)
|| STATUS_PENDING_RETURN_CONFIRM.equalsIgnoreCase(status);
}
/**
@@ -155,6 +159,9 @@ public final class WaybillProcessSupport {
if ("cancelled".equalsIgnoreCase(status)) {
return "运单已取消";
}
if (STATUS_PENDING_RETURN_CONFIRM.equalsIgnoreCase(status)) {
return "运单待业务员确认回单";
}
return null;
}
@@ -195,7 +202,7 @@ public final class WaybillProcessSupport {
* 上报异常前的运单状态门禁原因;可上报时返回 null。
* <p>
* 与打卡共用「已开始运输」判据,但文案说的是能不能报,不是能不能打。
* 结束优先于未开始:已完成/已取消的运单先说结束,不再提「等你上路」。
* 结束优先于未开始:已结束的运单先说结束,不再提「等你上路」。
*/
public static String reportBlockedReason(String businessStatus) {
String endedReason = punchEndedReason(businessStatus);
@@ -213,7 +220,8 @@ public final class WaybillProcessSupport {
|| "completed".equals(businessStatus)
|| "cancelled".equals(businessStatus)
|| "waiting_dispatch".equals(businessStatus)
|| "dispatching".equals(businessStatus);
|| "dispatching".equals(businessStatus)
|| STATUS_PENDING_RETURN_CONFIRM.equals(businessStatus);
}
/**
@@ -334,15 +334,31 @@ class WaybillProcessSupportTest {
"TRANSPORT_JSON 的回单启用且没有 confirmMode:缺字段当没配「无需确认完成」,否则会跳过本该人工确认的回单");
}
// ------------------------------------------------------------ 待回单确认
@Test
@DisplayName("待回单确认落库字面量为 pending_return_confirm,且接单归一不得改写它")
void pendingReturnConfirmIsTerminalStatus() {
assertEquals("pending_return_confirm", WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM,
"库里存的是这个字面量,web 与小程序也按它判断,不能改名");
assertEquals(WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM,
WaybillProcessSupport.normalizeBusinessStatus(WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM, TRANSPORT_JSON),
"TRANSPORT_JSON 要求确认接单,未接单时归一结果本是 pending;运单已跑完全程,不能被改回待执行");
assertEquals(WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM,
WaybillProcessSupport.normalizeBusinessStatus(WaybillProcessSupport.STATUS_PENDING_RETURN_CONFIRM, TRANSPORT_JSON, "accepted"));
}
// ------------------------------------------------------------ 结束门禁
@Test
@DisplayName("结束门禁:只认已完成与已取消,大小写不敏感")
void punchEndedOnlyForCompletedAndCancelled() {
@DisplayName("结束门禁:已完成、已取消与待回单确认都算结束,大小写不敏感")
void punchEndedForCompletedCancelledAndPendingReturnConfirm() {
assertTrue(WaybillProcessSupport.isPunchEnded("completed"));
assertTrue(WaybillProcessSupport.isPunchEnded("COMPLETED"));
assertTrue(WaybillProcessSupport.isPunchEnded("cancelled"));
assertTrue(WaybillProcessSupport.isPunchEnded("Cancelled"));
assertTrue(WaybillProcessSupport.isPunchEnded("pending_return_confirm"),
"司机已打完末位卡,不能再打卡");
}
@Test
@@ -358,11 +374,12 @@ class WaybillProcessSupportTest {
}
@Test
@DisplayName("结束门禁文案:完成与取消各一句,非结束态没有文案")
@DisplayName("结束门禁文案:完成、取消与待回单确认各一句,非结束态没有文案")
void punchEndedReasonOnlyForEndedStatuses() {
assertEquals("运单已完成", WaybillProcessSupport.punchEndedReason("completed"));
assertEquals("运单已完成", WaybillProcessSupport.punchEndedReason(" COMPLETED "));
assertEquals("运单已取消", WaybillProcessSupport.punchEndedReason("cancelled"));
assertEquals("运单待业务员确认回单", WaybillProcessSupport.punchEndedReason("pending_return_confirm"));
assertNull(WaybillProcessSupport.punchEndedReason(null));
assertNull(WaybillProcessSupport.punchEndedReason(""));
assertNull(WaybillProcessSupport.punchEndedReason(" "));
@@ -421,6 +438,22 @@ class WaybillProcessSupportTest {
// 结束态由结束文案负责,两句话不能抢
assertNull(WaybillProcessSupport.punchNotStartedReason("completed"));
assertNull(WaybillProcessSupport.punchNotStartedReason("cancelled"));
assertNull(WaybillProcessSupport.punchNotStartedReason("pending_return_confirm"),
"司机已打完末位卡,不能再被说成「尚未开始运输」");
}
@Test
@DisplayName("在途卡:待回单确认的运单与已完成同样不可打卡")
void transitCardOnPendingReturnConfirmWaybillIsVisibleButNotPunchable() {
LocalDateTime now = LocalDateTime.of(2026, 10, 20, 12, 0);
WaybillProcessSupport.TransitCheckinDecision decision =
WaybillProcessSupport.evaluateTransitCheckin(TRANSPORT_JSON, "pending_return_confirm", null, now);
assertTrue(decision.visible(), "卡片仍要下发,司机能回看");
assertFalse(decision.punchEnabled(), "末位卡已打完,在途卡不能再提交");
assertFalse(decision.doneToday());
assertFalse(decision.dueToday());
}
@Test
@@ -455,9 +488,11 @@ class WaybillProcessSupportTest {
assertNull(WaybillProcessSupport.reportBlockedReason("running"));
assertEquals("运单尚未开始运输,暂不可上报异常", WaybillProcessSupport.reportBlockedReason("pending"));
assertEquals("运单尚未开始运输,暂不可上报异常", WaybillProcessSupport.reportBlockedReason("dispatching"));
// 结束优先:已完成/已取消先说结束,不提「等你上路」
// 结束优先:已结束态先说结束,不提「等你上路」
assertEquals("运单已完成,不能上报异常", WaybillProcessSupport.reportBlockedReason("completed"));
assertEquals("运单已取消,不能上报异常", WaybillProcessSupport.reportBlockedReason("cancelled"));
assertEquals("运单待业务员确认回单,不能上报异常",
WaybillProcessSupport.reportBlockedReason("pending_return_confirm"));
}
}