diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/WaybillProcessSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/WaybillProcessSupport.java index 4462c3a3..3b9d920e 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/WaybillProcessSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/WaybillProcessSupport.java @@ -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 { } /** - * 运单已结束:已完成或已取消。此后不再接受司机打卡。 + * 运单已结束:已完成、已取消,或已打完末位卡停在待回单确认。此后不再接受司机打卡。 *
- * 只认这两个状态,大小写不敏感。草稿、待执行、待调度、调度中的运单司机仍要能打卡, + * 只认这三个状态,大小写不敏感。草稿、待执行、待调度、调度中的运单司机仍要能打卡, * 所以不能按 {@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。 *
* 与打卡共用「已开始运输」判据,但文案说的是能不能报,不是能不能打。 - * 结束优先于未开始:已完成/已取消的运单先说结束,不再提「等你上路」。 + * 结束优先于未开始:已结束的运单先说结束,不再提「等你上路」。 */ 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); } /** diff --git a/blade-service/blade-transport/src/test/java/org/springblade/transport/support/WaybillProcessSupportTest.java b/blade-service/blade-transport/src/test/java/org/springblade/transport/support/WaybillProcessSupportTest.java index b09c82c4..9408bfd6 100644 --- a/blade-service/blade-transport/src/test/java/org/springblade/transport/support/WaybillProcessSupportTest.java +++ b/blade-service/blade-transport/src/test/java/org/springblade/transport/support/WaybillProcessSupportTest.java @@ -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")); } }