✨ 运单过程判定补充到货卸货签收、末位打卡与回单无需确认完成三项
This commit is contained in:
+46
@@ -53,6 +53,7 @@ public final class WaybillProcessSupport {
|
||||
public static final String ACCEPT_REJECTED = "rejected";
|
||||
private static final String CONFIRM_YES = "yes";
|
||||
private static final String CONFIRM_NO_ACCEPT = "no_confirm_accept";
|
||||
private static final String CONFIRM_NO_COMPLETE = "no_confirm_complete";
|
||||
private static final String NODE_TRANSIT = "transit";
|
||||
private static final String NODE_TRANSIT_NAME = "在途";
|
||||
/** 异常处置终态:completed=已完成,revoked=已撤销。只有终态解除打卡门禁 */
|
||||
@@ -244,6 +245,21 @@ public final class WaybillProcessSupport {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 本次打卡的节点是否是司机可打卡节点的末位。
|
||||
* <p>
|
||||
* 末位取「司机可打卡节点」序列:接单与回单不打卡,不参与排位——
|
||||
* 回单只要启用就必然排在配置最末,按全部启用节点取末位会永远取到回单。
|
||||
*/
|
||||
public static boolean isLastDriverPunchNode(String processJson, String nodeCode) {
|
||||
List<Map<String, Object>> nodes = listDriverPunchNodes(processJson);
|
||||
if (nodes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String code = stringVal(nodeCode);
|
||||
return !code.isEmpty() && code.equals(nodeKey(nodes.get(nodes.size() - 1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用中的过程节点(按配置顺序,含接单/回单)。
|
||||
*/
|
||||
@@ -591,6 +607,36 @@ public final class WaybillProcessSupport {
|
||||
return isAcceptNode(stringVal(node.get("key")), stringVal(node.get("name")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否到货 / 卸货 / 签收节点:key 或中文名任一命中即算。
|
||||
*/
|
||||
public static boolean isDeliveryNode(String nodeCode, String nodeName) {
|
||||
String key = stringVal(nodeCode);
|
||||
String name = stringVal(nodeName);
|
||||
return "arrival".equals(key) || "到货".equals(name)
|
||||
|| "unload".equals(key) || "卸货".equals(name)
|
||||
|| "sign".equals(key) || "签收".equals(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回单是否无需确认完成:配置里没有回单节点、回单未启用,或启用且配置为「无需确认完成」。
|
||||
* <p>
|
||||
* 未启用的回单节点不看 confirmMode——没有回单环节就不会有人来确认;
|
||||
* 启用但 confirmMode 缺失按「需确认完成」算。
|
||||
*/
|
||||
public static boolean returnNeedsNoConfirmation(String processJson) {
|
||||
for (Map<String, Object> node : parseProcessNodes(processJson)) {
|
||||
if (!isReturnNode(node)) {
|
||||
continue;
|
||||
}
|
||||
if (!isEnabled(node)) {
|
||||
return true;
|
||||
}
|
||||
return CONFIRM_NO_COMPLETE.equals(stringVal(node.get("confirmMode")));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isTransitNode(Map<String, Object> node) {
|
||||
String key = stringVal(node.get("key"));
|
||||
String name = stringVal(node.get("name"));
|
||||
|
||||
+140
@@ -172,4 +172,144 @@ class WaybillProcessSupportTest {
|
||||
assertFalse(WaybillProcessSupport.sameNodeCode(null, null));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 到货/卸货/签收
|
||||
|
||||
@Test
|
||||
@DisplayName("到货/卸货/签收:key 或中文名任一命中即可,两者都为空不算")
|
||||
void deliveryNodeMatchesKeyOrName() {
|
||||
assertTrue(WaybillProcessSupport.isDeliveryNode("arrival", "到货"));
|
||||
assertTrue(WaybillProcessSupport.isDeliveryNode("unload", "卸货"));
|
||||
assertTrue(WaybillProcessSupport.isDeliveryNode("sign", "签收"));
|
||||
assertTrue(WaybillProcessSupport.isDeliveryNode("arrival", ""), "只有 key 也要认,别把中文名当必要条件");
|
||||
assertTrue(WaybillProcessSupport.isDeliveryNode("", "签收"), "只有中文名也要认——key 可能被改成自定义编码");
|
||||
assertFalse(WaybillProcessSupport.isDeliveryNode("dispatch", "发货"));
|
||||
assertFalse(WaybillProcessSupport.isDeliveryNode("transit", "在途"));
|
||||
assertFalse(WaybillProcessSupport.isDeliveryNode("", ""));
|
||||
assertFalse(WaybillProcessSupport.isDeliveryNode(null, null));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 末位司机打卡节点
|
||||
|
||||
/** 末位是「到货」,其后没有打卡节点 */
|
||||
private static final String ARRIVAL_LAST_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"arrival","name":"到货","enabled":true,"punch":true}]
|
||||
""";
|
||||
|
||||
/** 末位是「卸货」 */
|
||||
private static final String UNLOAD_LAST_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"unload","name":"卸货","enabled":true,"punch":true}]
|
||||
""";
|
||||
|
||||
/** 末位是「在途」 */
|
||||
private static final String TRANSIT_LAST_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"transit","name":"在途","type":"transit","enabled":true,"punch":true}]
|
||||
""";
|
||||
|
||||
/** 末位是「发货」 */
|
||||
private static final String DISPATCH_LAST_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"dispatch","name":"发货","enabled":true,"punch":true}]
|
||||
""";
|
||||
|
||||
@Test
|
||||
@DisplayName("末位打卡节点取「司机可打卡节点」的末位:接单与回单就算启用也不算")
|
||||
void lastDriverPunchNodeSkipsAcceptAndReturn() {
|
||||
assertTrue(WaybillProcessSupport.isLastDriverPunchNode(TRANSPORT_JSON, "sign"),
|
||||
"回单启用在配置里排最末,但回单不打卡,末位打卡节点仍是签收");
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(TRANSPORT_JSON, "unload"));
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(TRANSPORT_JSON, "arrival"));
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(TRANSPORT_JSON, "return"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("末位是签收 / 到货 / 卸货才同时成立「末位」与「到货卸货签收」;末位是在途 / 发货只满足前者")
|
||||
void lastNodeIsDeliveryOnlyForDeliveryTypes() {
|
||||
assertTrue(WaybillProcessSupport.isLastDriverPunchNode(TRANSPORT_JSON, "sign")
|
||||
&& WaybillProcessSupport.isDeliveryNode("sign", "签收"));
|
||||
assertTrue(WaybillProcessSupport.isLastDriverPunchNode(ARRIVAL_LAST_JSON, "arrival")
|
||||
&& WaybillProcessSupport.isDeliveryNode("arrival", "到货"));
|
||||
assertTrue(WaybillProcessSupport.isLastDriverPunchNode(UNLOAD_LAST_JSON, "unload")
|
||||
&& WaybillProcessSupport.isDeliveryNode("unload", "卸货"));
|
||||
assertTrue(WaybillProcessSupport.isLastDriverPunchNode(TRANSIT_LAST_JSON, "transit"),
|
||||
"在途排在末位时它确实是末位打卡节点");
|
||||
assertFalse(WaybillProcessSupport.isDeliveryNode("transit", "在途"), "在途不是可完成节点");
|
||||
assertTrue(WaybillProcessSupport.isLastDriverPunchNode(DISPATCH_LAST_JSON, "dispatch"));
|
||||
assertFalse(WaybillProcessSupport.isDeliveryNode("dispatch", "发货"), "发货不是可完成节点");
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(DISPATCH_LAST_JSON, "unload"),
|
||||
"该配置里没有卸货节点,不能因为编码眼熟就认下");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("没有可打卡节点(或没有过程配置)时,谁都不是末位")
|
||||
void lastDriverPunchNodeWithoutPunchNodes() {
|
||||
String onlyAcceptAndReturn = """
|
||||
[{"key":"accept","name":"接单","enabled":true,"punch":true},
|
||||
{"key":"return","name":"回单","type":"confirm","enabled":true,"punch":true}]
|
||||
""";
|
||||
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(onlyAcceptAndReturn, "accept"));
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(onlyAcceptAndReturn, "return"));
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode("", "sign"));
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(null, "sign"));
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(TRANSPORT_JSON, null));
|
||||
assertFalse(WaybillProcessSupport.isLastDriverPunchNode(TRANSPORT_JSON, ""));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------ 回单是否无需确认完成
|
||||
|
||||
/** 回单启用且配置为「无需确认完成」 */
|
||||
private static final String RETURN_NO_CONFIRM_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"sign","name":"签收","enabled":true,"punch":true},
|
||||
{"key":"return","name":"回单","type":"confirm","enabled":true,"punch":true,"confirmMode":"no_confirm_complete"}]
|
||||
""";
|
||||
|
||||
/** 回单启用且配置为「需确认完成」 */
|
||||
private static final String RETURN_NEED_CONFIRM_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"sign","name":"签收","enabled":true,"punch":true},
|
||||
{"key":"return","name":"回单","type":"confirm","enabled":true,"punch":true,"confirmMode":"yes"}]
|
||||
""";
|
||||
|
||||
/** 回单未启用,但 confirmMode 写着「需确认完成」 */
|
||||
private static final String RETURN_DISABLED_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"sign","name":"签收","enabled":true,"punch":true},
|
||||
{"key":"return","name":"回单","type":"confirm","enabled":false,"punch":true,"confirmMode":"yes"}]
|
||||
""";
|
||||
|
||||
/** 配置里根本没有回单节点 */
|
||||
private static final String NO_RETURN_JSON = """
|
||||
[{"key":"load","name":"装货","enabled":true,"punch":true},
|
||||
{"key":"sign","name":"签收","enabled":true,"punch":true}]
|
||||
""";
|
||||
|
||||
@Test
|
||||
@DisplayName("回单启用时要看 confirmMode:只有「无需确认完成」才成立")
|
||||
void enabledReturnNeedsConfirmMode() {
|
||||
assertTrue(WaybillProcessSupport.returnNeedsNoConfirmation(RETURN_NO_CONFIRM_JSON));
|
||||
assertFalse(WaybillProcessSupport.returnNeedsNoConfirmation(RETURN_NEED_CONFIRM_JSON),
|
||||
"回单需要确认完成时,打完签收不能算整单完成");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("回单未启用、或配置里没有回单节点,一律视为无需确认完成")
|
||||
void absentOrDisabledReturnNeedsNoConfirmation() {
|
||||
assertTrue(WaybillProcessSupport.returnNeedsNoConfirmation(RETURN_DISABLED_JSON),
|
||||
"回单未启用时 confirmMode 写着需确认也不算数:没启用的环节不会有人来确认");
|
||||
assertTrue(WaybillProcessSupport.returnNeedsNoConfirmation(NO_RETURN_JSON));
|
||||
assertTrue(WaybillProcessSupport.returnNeedsNoConfirmation(""));
|
||||
assertTrue(WaybillProcessSupport.returnNeedsNoConfirmation(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("回单启用但 confirmMode 缺失时按「需确认完成」算")
|
||||
void enabledReturnWithoutConfirmModeNeedsConfirmation() {
|
||||
assertFalse(WaybillProcessSupport.returnNeedsNoConfirmation(TRANSPORT_JSON),
|
||||
"TRANSPORT_JSON 的回单启用且没有 confirmMode:缺字段当没配「无需确认完成」,否则会跳过本该人工确认的回单");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user