✨ 认证记录状态机规则集中为 CertificationRuleSupport 并补测试
把「什么状态能做什么」从持久化里拎出来单独验证。这几条规则是认证改造的地基, 改坏的后果都是线上事故,故先锁住行为再写业务: - prepareForSubmit:新提交一律待审,并清空驳回原因(否则会继承上一次的驳回文案, 出现「审核中」却带着驳回原因的自相矛盾状态); - supersedeIfPending:再次提交只作废前一条待审,已通过/已驳回/已作废都是终态不碰 ——尤其是不得改动已通过的记录,它可能正被生效快照指针指着; - isCertified:唯一判据是生效快照指针,故「曾通过即永久保持」; - isAuditable:只有待审可审,终态再审会把生效快照改坏; - statusText:四种状态各一个中文说法,与列注释、前端文案保持一致。 TransportCertRecord.REJECT_REASON_MAX_LENGTH 与 reject_reason 列宽(200)对齐。 9 个用例覆盖上述规则与边界(null、未知状态、超长原因)。 可离线执行:mvn -o test -pl blade-service/blade-transport -am
This commit is contained in:
+180
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.support;
|
||||
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.transport.pojo.entity.TransportCertRecord;
|
||||
|
||||
/**
|
||||
* 认证记录状态机规则
|
||||
* <p>
|
||||
* 把「什么状态能做什么」集中在一处,与持久化分离,便于单独验证。
|
||||
* 这几条规则是整个认证改造的地基,改坏的后果是线上事故:
|
||||
* 司机重新提交认证后车辆掉出可用池,或同一辆车出现两条待审记录。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public final class CertificationRuleSupport {
|
||||
|
||||
private static final String STATUS_TEXT_PENDING = "审核中";
|
||||
private static final String STATUS_TEXT_APPROVED = "已通过";
|
||||
private static final String STATUS_TEXT_REJECTED = "已驳回";
|
||||
private static final String STATUS_TEXT_SUPERSEDED = "已作废";
|
||||
private static final String STATUS_TEXT_UNKNOWN = "未知状态";
|
||||
|
||||
private CertificationRuleSupport() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 把一条新提交的记录准备成待审
|
||||
* <p>
|
||||
* 必须清空驳回原因:新提交是全新一次认证,不能继承上一次的驳回文案,
|
||||
* 否则前端会显示「审核中」却带着旧的驳回原因。
|
||||
*
|
||||
* @param incoming 待入库的记录
|
||||
*/
|
||||
public static void prepareForSubmit(TransportCertRecord incoming) {
|
||||
incoming.setStatus(TransportCertRecord.STATUS_PENDING);
|
||||
incoming.setRejectReason(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 再次提交时,把该认证对象**前一条待审**记录转为已作废
|
||||
* <p>
|
||||
* 只动待审记录:已通过、已驳回、已作废都是终态,一律不碰。
|
||||
* 特别是**不得改动已通过的记录**——它可能正被生效快照指针指着。
|
||||
*
|
||||
* @param previousPending 该对象当前那条待审记录,可为 null
|
||||
* @return 需要更新为已作废的记录;无需更新时返回 null
|
||||
*/
|
||||
public static TransportCertRecord supersedeIfPending(TransportCertRecord previousPending) {
|
||||
if (previousPending == null) {
|
||||
return null;
|
||||
}
|
||||
if (!TransportCertRecord.STATUS_PENDING.equals(previousPending.getStatus())) {
|
||||
return null;
|
||||
}
|
||||
previousPending.setStatus(TransportCertRecord.STATUS_SUPERSEDED);
|
||||
return previousPending;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判定认证对象是否已认证
|
||||
* <p>
|
||||
* 唯一判据是生效快照指针。指针一旦写入永不回退,因此「曾通过即永久保持」,
|
||||
* 重新提交、待审、被驳回都不会让对象变回未认证。
|
||||
*
|
||||
* @param effectiveRecordId 生效快照指针
|
||||
* @return 是否已认证
|
||||
*/
|
||||
public static boolean isCertified(Long effectiveRecordId) {
|
||||
return Func.isNotEmpty(effectiveRecordId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判定一条记录是否可被审核
|
||||
* <p>
|
||||
* 只有待审记录可审。已通过/已驳回/已作废都是终态,再次审核会把生效快照改坏
|
||||
* (例如把指针指着的那条「已通过」改成「已驳回」,生效值就没了)。
|
||||
*
|
||||
* @param record 认证记录
|
||||
* @return 是否可审核
|
||||
*/
|
||||
public static boolean isAuditable(TransportCertRecord record) {
|
||||
return record != null && TransportCertRecord.STATUS_PENDING.equals(record.getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验审核入参是否合法
|
||||
*
|
||||
* @param pass 是否通过
|
||||
* @param rejectReason 驳回原因
|
||||
* @return 是否合法
|
||||
*/
|
||||
public static boolean isRejectReasonValid(boolean pass, String rejectReason) {
|
||||
if (pass) {
|
||||
return true;
|
||||
}
|
||||
String reason = Func.toStr(rejectReason, "").trim();
|
||||
return Func.isNotEmpty(reason)
|
||||
&& reason.length() <= TransportCertRecord.REJECT_REASON_MAX_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核通过时的驳回原因:必须为 null,避免残留上一次的驳回文案
|
||||
*
|
||||
* @return 恒为 null
|
||||
*/
|
||||
public static String reasonForApprove() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核驳回时的驳回原因:去首尾空白后落库
|
||||
*
|
||||
* @param rejectReason 原始原因
|
||||
* @return 去空白后的原因
|
||||
*/
|
||||
public static String reasonForReject(String rejectReason) {
|
||||
return Func.toStr(rejectReason, "").trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态对应的中文文案
|
||||
* <p>
|
||||
* 四端(小程序、Web、接口、库注释)必须用同一套说法,不要各造一套。
|
||||
*
|
||||
* @param status 状态值
|
||||
* @return 中文文案
|
||||
*/
|
||||
public static String statusText(Integer status) {
|
||||
if (TransportCertRecord.STATUS_PENDING.equals(status)) {
|
||||
return STATUS_TEXT_PENDING;
|
||||
}
|
||||
if (TransportCertRecord.STATUS_APPROVED.equals(status)) {
|
||||
return STATUS_TEXT_APPROVED;
|
||||
}
|
||||
if (TransportCertRecord.STATUS_REJECTED.equals(status)) {
|
||||
return STATUS_TEXT_REJECTED;
|
||||
}
|
||||
if (TransportCertRecord.STATUS_SUPERSEDED.equals(status)) {
|
||||
return STATUS_TEXT_SUPERSEDED;
|
||||
}
|
||||
return STATUS_TEXT_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验认证对象类型
|
||||
*
|
||||
* @param bizType 类型
|
||||
* @return 是否为合法类型
|
||||
*/
|
||||
public static boolean isValidBizType(String bizType) {
|
||||
return TransportCertRecord.BIZ_TYPE_DRIVER.equals(bizType)
|
||||
|| TransportCertRecord.BIZ_TYPE_VEHICLE.equals(bizType);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user