搜 索

FAB SVA 退出 - 余额清空功能设计文档

  • 5阅读
  • 2026年04月08日
  • 0评论
首页 / Default / 正文
版本: v1.0
日期: 2026-04-08
模块: gp104_escrow

1. 背景与目标

1.1 背景

PayBy 决定退出 FAB 的 SVA(Stored Value Account)功能。退出前需将所有 SVA 卡上的余额清空(归零),确保 Pool Account 资金与卡余额一致归零后,完成业务退出。

1.2 目标

  • 基于 FAB 提供的余额文件,与系统内余额进行比对核验
  • 在确认一致后,生成余额清空交易列表,逐笔报送 FAB
  • 处理因卡状态异常导致的报送失败,通过与 FAB 协调修复后重新报送
  • 最终实现所有卡余额清零,Pool Account 余额归零

1.3 约束条件

  • 所有卡总余额 = Pool Account 余额(FAB 提供的文件需满足此等式)
  • 需要设定一个系统截止时间点(Cutoff Time),截止后不再接受新交易
  • 余额清空为不可逆操作,需经过 Operator 确认后方可执行

2. 整体流程概览

flowchart TD A[FAB 提供余额文件] --> B[Operator 通过 Counter 上传余额文件] B --> C[设定系统截止时间点 Cutoff Time] C --> D[系统生成内部余额快照] D --> E[余额比对: FAB文件 vs 系统快照] E --> F{比对结果} F -->|一致| G[生成汇总报告] F -->|不一致| H[生成差异明细报告] H --> I[Operator 审核差异] I -->|确认差异可接受| G I -->|需要调整| J[与 FAB 协调处理差异] J --> A G --> K[Operator 确认提交] K --> L[生成余额清空交易列表] L --> M[逐批报送 FAB] M --> N{报送结果} N -->|全部成功| O[余额清空完成] N -->|部分失败| P[生成失败卡列表] P --> Q[发送失败列表给 FAB 修改卡状态] Q --> R[FAB 修复卡状态] R --> M O --> S[Pool Account 余额归零确认]

3. 详细流程设计

3.1 阶段一:余额文件上传与截止时间设定

sequenceDiagram participant FAB as FAB Bank participant OP as Operator participant CT as Counter (UI) participant SYS as Escrow System participant UFS as UFS 文件服务 FAB->>OP: 提供余额文件(CSV) OP->>CT: 上传余额文件 + 设定截止时间 CT->>UFS: 存储余额文件 UFS-->>CT: 返回 fileTag CT->>SYS: 发起余额清空请求(fileTag + cutoffTime) SYS->>SYS: 创建清空批次记录(ClearingBatch) SYS->>SYS: 设定系统截止时间 SYS-->>CT: 返回批次号(clearingBatchId)

FAB 余额文件格式(CSV):

字段说明示例
CardID卡ID1234567890
Balance卡余额(AED)150.00

文件末尾包含汇总行:

字段说明
Total Cards卡总数
Total Balance总余额(应等于 Pool Account 余额)

3.2 阶段二:系统余额快照生成

sequenceDiagram participant SYS as Escrow System participant DB as Database participant QRY as Query Service SYS->>SYS: 触发余额快照(cutoffTime) SYS->>DB: 查询所有活跃卡列表(t_issue_record + t_card_detail) DB-->>SYS: 卡列表(cardId, memberId) loop 分批处理(batch_size=200) SYS->>QRY: 查询会员账户余额(BASIC + RED_PACKET_SETTLE + OUTER_TRANSFER_SETTLE) QRY-->>SYS: 各账户类型余额 SYS->>SYS: 汇总每张卡的系统总余额 SYS->>DB: 存储余额快照明细(t_clearing_balance_detail) end SYS->>DB: 更新批次状态为 SNAPSHOT_DONE

3.3 阶段三:余额比对

sequenceDiagram participant SYS as Escrow System participant UFS as UFS 文件服务 participant DB as Database SYS->>UFS: 下载 FAB 余额文件 UFS-->>SYS: 文件内容 SYS->>SYS: 解析 CSV 文件 SYS->>DB: 读取系统余额快照 SYS->>SYS: 逐卡比对 Note over SYS: FAB余额 vs 系统余额(BASIC+RED_PACKET+TRANSFER) alt 完全匹配 SYS->>DB: 标记明细状态为 MATCHED else 金额不一致 SYS->>DB: 标记明细状态为 MISMATCHED, 记录差异金额 else FAB文件中有但系统无 SYS->>DB: 标记为 FAB_ONLY else 系统有但FAB文件无 SYS->>DB: 标记为 SYSTEM_ONLY end SYS->>SYS: 生成汇总信息 SYS->>DB: 更新批次状态为 RECONCILED, 存储汇总

比对汇总信息

总卡数(FAB):        1500
总卡数(系统):       1500
匹配成功:           1485
金额不一致:         10
仅FAB存在:          3
仅系统存在:         2
FAB总余额:          500,000.00 AED
系统总余额:         500,000.00 AED
差异总额:           150.00 AED

3.4 阶段四:确认与生成清空交易

sequenceDiagram participant OP as Operator participant CT as Counter (UI) participant SYS as Escrow System participant DB as Database OP->>CT: 查看比对汇总和差异明细 OP->>CT: 确认提交(clearingBatchId) CT->>SYS: 提交确认请求 SYS->>DB: 查询所有余额>0的卡 loop 每张有余额的卡 SYS->>SYS: 创建扣减交易记录 Note over SYS: amount = 卡余额
direction = negative
afterBalance = 0 SYS->>DB: 插入 t_clearing_transaction end SYS->>DB: 更新批次状态为 CONFIRMED SYS->>SYS: 生成清空交易汇总 SYS-->>CT: 返回交易列表汇总

3.5 阶段五:交易报送 FAB

sequenceDiagram participant SYS as Escrow System participant DB as Database participant WAVE as Wave/FAB Channel participant FAB as FAB Bank SYS->>DB: 查询待报送交易(status=INIT) loop 分批报送(batch) SYS->>WAVE: 报送扣减交易 WAVE->>FAB: 发送交易请求 FAB-->>WAVE: 返回处理结果 WAVE-->>SYS: 报送结果 alt 成功 SYS->>DB: 更新交易状态为 SUCCESS else 失败(卡状态异常) SYS->>DB: 更新交易状态为 FAILED, 记录失败原因 end end SYS->>DB: 更新批次进度

3.6 阶段六:失败重试流程

flowchart TD A[报送完成, 存在失败记录] --> B[生成失败卡列表文件] B --> C[Operator 下载失败列表] C --> D[发送给 FAB 请求修复卡状态] D --> E[FAB 修复卡状态] E --> F[FAB 确认修复完成] F --> G[Operator 通过 Counter 触发重新报送] G --> H[系统重新报送失败交易] H --> I{全部成功?} I -->|是| J[本轮清空完成] I -->|否| B J --> K{所有交易完成?} K -->|是| L[余额清空全部完成] K -->|否| A
sequenceDiagram participant OP as Operator participant CT as Counter (UI) participant SYS as Escrow System participant FAB as FAB Bank SYS->>SYS: 汇总失败交易列表 SYS->>SYS: 生成失败卡列表文件(CSV) OP->>CT: 下载失败列表 OP->>FAB: 邮件发送失败卡列表, 请求修复状态 FAB->>FAB: 修复卡状态(解冻/激活等) FAB->>OP: 确认修复完成 OP->>CT: 触发重新报送(clearingBatchId) CT->>SYS: 重试报送请求 SYS->>SYS: 查询 FAILED 状态交易 SYS->>FAB: 重新报送 FAB-->>SYS: 返回结果 alt 全部成功 SYS->>SYS: 更新批次状态为 COMPLETED else 仍有失败 SYS->>SYS: 更新失败记录, 等待下轮处理 end

4. 状态机设计

4.1 清空批次状态(ClearingBatch)

stateDiagram-v2 [*] --> INIT: 创建批次 INIT --> SNAPSHOT_DONE: 余额快照完成 SNAPSHOT_DONE --> RECONCILED: 余额比对完成 RECONCILED --> CONFIRMED: Operator确认提交 CONFIRMED --> REPORTING: 开始报送 REPORTING --> PARTIALLY_DONE: 部分成功/部分失败 REPORTING --> COMPLETED: 全部报送成功 PARTIALLY_DONE --> REPORTING: 重新报送失败交易 PARTIALLY_DONE --> COMPLETED: 重试后全部成功 COMPLETED --> [*] INIT --> CANCELLED: 取消 SNAPSHOT_DONE --> CANCELLED: 取消 RECONCILED --> CANCELLED: 取消 CANCELLED --> [*]

4.2 清空交易状态(ClearingTransaction)

stateDiagram-v2 [*] --> INIT: 生成交易记录 INIT --> PROCESSING: 开始报送 PROCESSING --> SUCCESS: FAB返回成功 PROCESSING --> FAILED: FAB返回失败 FAILED --> PROCESSING: 重新报送 SUCCESS --> [*]

4.3 余额比对明细状态(ClearingBalanceDetail)

stateDiagram-v2 [*] --> PENDING: 快照生成 PENDING --> MATCHED: 比对一致 PENDING --> MISMATCHED: 金额不一致 PENDING --> FAB_ONLY: 仅FAB存在 PENDING --> SYSTEM_ONLY: 仅系统存在 MATCHED --> [*] MISMATCHED --> [*] FAB_ONLY --> [*] SYSTEM_ONLY --> [*]

5. 数据库设计

5.1 新增表

t_clearing_batch(清空批次表)

字段类型说明
clearing_batch_idBIGINT AUTO_INCREMENT主键
batch_noVARCHAR(64)批次号(唯一)
bank_codeVARCHAR(16)银行编码: FAB
cutoff_timeDATETIME系统截止时间
fab_file_tagVARCHAR(256)FAB余额文件 UFS fileTag
fab_total_cardsINTFAB文件卡总数
fab_total_balanceDECIMAL(18,2)FAB文件总余额
sys_total_cardsINT系统卡总数
sys_total_balanceDECIMAL(18,2)系统总余额
matched_countINT匹配成功数
mismatched_countINT不匹配数
fab_only_countINT仅FAB存在数
sys_only_countINT仅系统存在数
diff_amountDECIMAL(18,2)差异总额
total_transactionsINT总交易数
success_countINT报送成功数
failed_countINT报送失败数
statusVARCHAR(20)批次状态
operatorVARCHAR(64)操作人
memoVARCHAR(512)备注
gmt_createDATETIME创建时间
gmt_modifiedDATETIME修改时间

t_clearing_balance_detail(余额比对明细表)

字段类型说明
detail_idBIGINT AUTO_INCREMENT主键
clearing_batch_idBIGINT批次ID
card_idVARCHAR(64)卡ID
member_idVARCHAR(64)会员ID
fab_balanceDECIMAL(18,2)FAB文件中余额
sys_basic_balanceDECIMAL(18,2)系统BASIC账户余额
sys_red_packet_balanceDECIMAL(18,2)系统RED_PACKET_SETTLE余额
sys_transfer_balanceDECIMAL(18,2)系统OUTER_TRANSFER_SETTLE余额
sys_total_balanceDECIMAL(18,2)系统汇总余额
diff_amountDECIMAL(18,2)差异金额
currencyVARCHAR(8)币种: AED
statusVARCHAR(20)比对状态: PENDING/MATCHED/MISMATCHED/FAB_ONLY/SYSTEM_ONLY
memoVARCHAR(512)备注
gmt_createDATETIME创建时间
gmt_modifiedDATETIME修改时间

t_clearing_transaction(清空交易表)

字段类型说明
transaction_idBIGINT AUTO_INCREMENT主键
clearing_batch_idBIGINT批次ID
card_idVARCHAR(64)卡ID
member_idVARCHAR(64)会员ID
amountDECIMAL(18,2)扣减金额
currencyVARCHAR(8)币种: AED
directionVARCHAR(16)方向: negative
before_balanceDECIMAL(18,2)扣减前余额
after_balanceDECIMAL(18,2)扣减后余额(应为0)
report_statusVARCHAR(16)报送状态: INIT/PROCESSING/SUCCESS/FAILED
fail_reasonVARCHAR(512)失败原因
fail_countINT DEFAULT 0失败次数
fab_response_codeVARCHAR(32)FAB响应码
fab_response_msgVARCHAR(512)FAB响应信息
report_timeDATETIME报送时间
report_success_timeDATETIME报送成功时间
memoVARCHAR(512)备注
gmt_createDATETIME创建时间
gmt_modifiedDATETIME修改时间

5.2 索引设计

-- t_clearing_batch
CREATE UNIQUE INDEX uk_batch_no ON t_clearing_batch(batch_no);
CREATE INDEX idx_status ON t_clearing_batch(status);

-- t_clearing_balance_detail
CREATE INDEX idx_batch_id ON t_clearing_balance_detail(clearing_batch_id);
CREATE INDEX idx_card_id ON t_clearing_balance_detail(card_id);
CREATE INDEX idx_status ON t_clearing_balance_detail(clearing_batch_id, status);

-- t_clearing_transaction
CREATE INDEX idx_batch_id ON t_clearing_transaction(clearing_batch_id);
CREATE INDEX idx_card_id ON t_clearing_transaction(card_id);
CREATE INDEX idx_report_status ON t_clearing_transaction(clearing_batch_id, report_status);
CREATE INDEX idx_member_id ON t_clearing_transaction(member_id);

6. 接口设计

6.1 CounterFacade 新增接口

/**
 * 余额清空 - 创建清空批次(上传文件+设定截止时间)
 */
CommonResponse clearingBatchCreate(ClearingBatchCreateRequest request);

/**
 * 余额清空 - 查询批次详情
 */
ClearingBatchDetailResponse clearingBatchDetail(ClearingBatchDetailRequest request);

/**
 * 余额清空 - 查询比对明细列表(分页)
 */
ClearingBalanceDetailListResponse clearingBalanceDetailList(ClearingBalanceDetailListRequest request);

/**
 * 余额清空 - 查询清空交易列表(分页)
 */
ClearingTransactionListResponse clearingTransactionList(ClearingTransactionListRequest request);

/**
 * 余额清空 - Operator确认提交
 */
CommonResponse clearingBatchConfirm(ClearingBatchConfirmRequest request);

/**
 * 余额清空 - 触发报送/重新报送
 */
CommonResponse clearingBatchReport(ClearingBatchReportRequest request);

/**
 * 余额清空 - 导出失败卡列表
 */
ExportFailedCardsResponse clearingExportFailedCards(ClearingExportFailedCardsRequest request);

6.2 请求/响应模型

// 创建清空批次请求
public class ClearingBatchCreateRequest {
    private String fabFileTag;      // FAB余额文件 UFS fileTag
    private Date cutoffTime;        // 系统截止时间
    private String operator;        // 操作人
    private String memo;            // 备注
}

// 批次详情响应
public class ClearingBatchDetailResponse extends CommonResponse {
    private String batchNo;
    private String status;
    private Date cutoffTime;
    // 比对汇总
    private Integer fabTotalCards;
    private BigDecimal fabTotalBalance;
    private Integer sysTotalCards;
    private BigDecimal sysTotalBalance;
    private Integer matchedCount;
    private Integer mismatchedCount;
    private BigDecimal diffAmount;
    // 报送进度
    private Integer totalTransactions;
    private Integer successCount;
    private Integer failedCount;
}

// 确认提交请求
public class ClearingBatchConfirmRequest {
    private Long clearingBatchId;
    private String operator;
}

// 触发报送请求
public class ClearingBatchReportRequest {
    private Long clearingBatchId;
    private Boolean retryFailedOnly;  // true=仅重试失败的, false=全量报送
    private String operator;
}

// 导出失败卡列表响应
public class ExportFailedCardsResponse extends CommonResponse {
    private String fileUrl;           // 失败卡列表文件下载URL
    private Integer failedCount;
}

7. 系统模块变更

7.1 模块变更总览

graph LR subgraph "service/facade" A1[CounterFacade
+7个新接口] A2[新增 Request/Response] A3[新增 ClearingStatus 枚举] end subgraph "ext/service" B1[CounterFacadeImpl
新增实现] B2[ClearingProcessor
核心处理器] B3[ClearingReportTaskHandler
报送任务处理] end subgraph "domainservice" C1[ClearingBatchService] C2[ClearingBalanceDetailService] C3[ClearingTransactionService] end subgraph "core/dal" D1[t_clearing_batch] D2[t_clearing_balance_detail] D3[t_clearing_transaction] D4[对应 DO/Mapper/XML] end subgraph "core/domain" E1[ClearingBatchDomain] E2[ClearingBalanceDetailDomain] E3[ClearingTransactionDomain] end subgraph "core/common" F1[ClearingBatchStatus 枚举] F2[ClearingTransactionStatus 枚举] F3[ClearingBalanceStatus 枚举] end subgraph "ext/integration" G1[复用 Wave/FAB Channel] G2[复用 QueryClient] G3[复用 UfsServiceClient] end A1 --> B1 B1 --> B2 B2 --> C1 B2 --> C2 B2 --> C3 B2 --> G1 B2 --> G2 B2 --> G3 C1 --> D1 C2 --> D2 C3 --> D3

7.2 各模块详细变更

模块变更类型具体内容
service/facade新增ClearingBatchCreateRequest, ClearingBatchDetailRequest/Response, ClearingBalanceDetailListRequest/Response, ClearingTransactionListRequest/Response, ClearingBatchConfirmRequest, ClearingBatchReportRequest, ClearingExportFailedCardsRequest/Response
service/facade修改CounterFacade 新增 7 个接口方法
service/facade新增ClearingBatchStatusEnum, ClearingTransactionStatusEnum, ClearingBalanceStatusEnum
ext/service修改CounterFacadeImpl 新增接口实现
ext/service新增ClearingProcessor - 余额清空核心处理器
ext/service新增ClearingReportTaskHandler - 报送任务异步处理
ext/service新增ClearingFileParser - FAB 余额文件解析
ext/service新增ClearingConvert - 对象转换器
domainservice新增ClearingBatchService / ClearingBalanceDetailService / ClearingTransactionService
domainservice新增对应 Repository 实现
core/domain新增ClearingBatchDomain, ClearingBalanceDetailDomain, ClearingTransactionDomain
core/dal新增3 张表对应的 DO、Mapper 接口、MyBatis XML 映射文件
core/common新增状态枚举类
ext/integration复用FabWaveChannelImpl, QueryClient, UfsServiceClient

8. 操作流程(SOP)

8.1 完整操作流程

flowchart TD subgraph "Phase 1: 准备" P1[1. 与 FAB 协调确定退出日期和截止时间] P2[2. FAB 导出全量卡余额文件] P3[3. FAB 邮件发送余额文件给 Operator] P1 --> P2 --> P3 end subgraph "Phase 2: 上传与比对" U1[4. Operator 登录 Counter 系统] U2[5. 进入'余额清空'功能页面] U3[6. 上传 FAB 余额文件] U4[7. 设定截止时间 Cutoff Time] U5[8. 点击'创建批次'按钮] U6[9. 系统自动执行:
- 生成余额快照
- 执行余额比对
- 生成汇总报告] U7[10. Operator 查看比对汇总] U8[11. Operator 查看差异明细] U1 --> U2 --> U3 --> U4 --> U5 --> U6 --> U7 --> U8 end subgraph "Phase 3: 确认与报送" C1[12. Operator 确认比对结果, 点击'确认提交'] C2[13. 系统生成清空交易列表] C3[14. Operator 查看交易列表] C4[15. 点击'开始报送'] C5[16. 系统逐批报送至 FAB] C6[17. 查看报送进度] C1 --> C2 --> C3 --> C4 --> C5 --> C6 end subgraph "Phase 4: 失败处理" F1[18. 查看报送结果] F2{全部成功?} F3[19. 导出失败卡列表] F4[20. 邮件发送失败列表给 FAB] F5[21. FAB 修复卡状态后回复确认] F6[22. Operator 点击'重新报送'] F7[23. 完成! 确认 Pool Account 余额归零] F1 --> F2 F2 -->|否| F3 --> F4 --> F5 --> F6 --> F1 F2 -->|是| F7 end P3 --> U1 U8 --> C1 C6 --> F1

8.2 Counter UI 页面设计

页面 1:余额清空 - 创建批次

+----------------------------------------------------------+
|  余额清空管理                                              |
+----------------------------------------------------------+
|  FAB 余额文件:  [选择文件...]  balance_20260408.csv        |
|  截止时间:      [2026-04-08 23:59:59]                     |
|  备注:          [SVA退出余额清空]                           |
|                                                          |
|  [创建批次]                                               |
+----------------------------------------------------------+

页面 2:批次详情与比对汇总

+----------------------------------------------------------+
|  批次号: CLR202604080001    状态: RECONCILED               |
+----------------------------------------------------------+
|  比对汇总                                                  |
|  ┌──────────────┬──────────┬──────────┐                   |
|  │              │ FAB文件   │ 系统快照  │                   |
|  ├──────────────┼──────────┼──────────┤                   |
|  │ 卡总数       │ 1,500    │ 1,500    │                   |
|  │ 总余额(AED)  │ 500,000  │ 500,000  │                   |
|  └──────────────┴──────────┴──────────┘                   |
|                                                          |
|  匹配: 1,485  |  不匹配: 10  |  仅FAB: 3  |  仅系统: 2    |
|                                                          |
|  [查看差异明细]  [确认提交]  [取消]                         |
+----------------------------------------------------------+

页面 3:报送进度

+----------------------------------------------------------+
|  批次号: CLR202604080001    状态: REPORTING                |
+----------------------------------------------------------+
|  报送进度                                                  |
|  ████████████████░░░░  80% (1200/1500)                   |
|                                                          |
|  成功: 1,180  |  失败: 20  |  待处理: 300                  |
|                                                          |
|  [查看失败列表]  [导出失败列表]  [重新报送]                  |
+----------------------------------------------------------+

9. 核心处理器伪代码

9.1 ClearingProcessor

@Component
public class ClearingProcessor {

    /** 创建清空批次 */
    public String createBatch(ClearingBatchCreateRequest request) {
        // 1. 校验:不能有正在进行中的批次
        // 2. 生成批次号 CLR + yyyyMMdd + seq
        // 3. 存储批次记录(状态=INIT)
        // 4. 异步执行:余额快照 + 比对
        asyncExecuteSnapshotAndReconcile(batchId, request);
        return batchNo;
    }

    /** 异步执行快照和比对 */
    @Async
    public void asyncExecuteSnapshotAndReconcile(Long batchId, ClearingBatchCreateRequest request) {
        // Phase 1: 生成系统余额快照
        generateSystemBalanceSnapshot(batchId, request.getCutoffTime());
        // Phase 2: 解析 FAB 文件并比对
        reconcileBalance(batchId, request.getFabFileTag());
    }

    /** 生成系统余额快照 */
    private void generateSystemBalanceSnapshot(Long batchId, Date cutoffTime) {
        // 1. 查询所有活跃卡(通过 t_issue_record + t_card_detail)
        // 2. 分批查询 Query 服务获取各账户类型余额
        // 3. 汇总每张卡余额 = BASIC + RED_PACKET_SETTLE + OUTER_TRANSFER_SETTLE
        // 4. 批量存入 t_clearing_balance_detail(status=PENDING)
        // 5. 更新批次状态为 SNAPSHOT_DONE
    }

    /** 余额比对 */
    private void reconcileBalance(Long batchId, String fabFileTag) {
        // 1. 下载并解析 FAB 余额文件
        // 2. 构建 Map<cardId, fabBalance>
        // 3. 读取系统快照 Map<cardId, sysBalance>
        // 4. 逐卡比对,更新明细状态
        // 5. 统计汇总信息,更新批次
        // 6. 更新批次状态为 RECONCILED
    }

    /** Operator确认后生成清空交易 */
    public void confirmAndGenerateTransactions(Long batchId) {
        // 1. 校验批次状态 == RECONCILED
        // 2. 查询所有余额 > 0 的明细
        // 3. 为每张卡生成扣减交易(t_clearing_transaction)
        //    - amount = 卡余额
        //    - direction = negative
        //    - after_balance = 0
        //    - report_status = INIT
        // 4. 更新批次状态为 CONFIRMED
    }

    /** 报送交易至 FAB */
    @Async
    public void reportTransactions(Long batchId, boolean retryFailedOnly) {
        // 1. 更新批次状态为 REPORTING
        // 2. 查询待报送交易
        //    retryFailedOnly ? status=FAILED : status=INIT
        // 3. 分批报送(复用 FabWaveChannelImpl)
        // 4. 逐笔更新报送结果
        // 5. 汇总:若全部成功 -> COMPLETED,否则 -> PARTIALLY_DONE
    }

    /** 导出失败卡列表 */
    public String exportFailedCards(Long batchId) {
        // 1. 查询 status=FAILED 的交易
        // 2. 生成 CSV 文件(cardId, amount, failReason)
        // 3. 上传至 UFS
        // 4. 返回下载 URL
    }
}

10. 异常处理与边界情况

10.1 异常处理策略

异常场景处理方式
FAB 文件格式错误解析失败,批次标记为 INIT,提示 Operator 重新上传
系统余额查询超时重试3次,仍失败则批次标记为失败,需重新创建
报送过程中网络中断已报送的记录保持状态不变,未报送的保持 INIT,可续传
FAB 返回未知错误码标记为 FAILED,记录原始响应,人工介入处理
重复报送同一笔交易使用幂等键(batchNo+cardId)防止重复扣减
截止时间后有新交易入账系统截止后应阻止新交易,通过配置开关控制

10.2 幂等性保证

  • 每笔清空交易使用 batchNo + cardId 作为幂等键
  • 报送前检查交易状态,已成功的不重复报送
  • FAB 侧通过交易流水号去重

10.3 数据一致性

flowchart LR A[系统截止] --> B[快照时间 = 截止时间] B --> C[FAB文件时间 = 截止时间] C --> D[三方数据时间点一致] D --> E[比对结果可信]

11. 配置项

# 余额清空相关配置
escrow:
  clearing:
    # 报送批次大小
    report-batch-size: 50
    # 快照查询批次大小
    snapshot-batch-size: 200
    # 报送重试最大次数
    max-retry-count: 5
    # 报送间隔(ms),避免FAB限流
    report-interval: 200
    # 临时文件路径
    temp-file-path: /tmp/escrow/clearing
    # 是否启用截止时间交易阻断
    cutoff-block-enabled: true

12. 安全与审计

  • 所有操作需记录操作人和操作时间
  • 确认提交操作需要 Operator 权限验证
  • 批次创建和确认操作需记录审计日志
  • FAB 余额文件下载后需验证文件完整性
  • 清空交易不可回滚,确认前需二次确认弹窗

13. 测试方案

测试类型测试内容
单元测试文件解析、余额比对逻辑、状态转换
集成测试完整流程:上传->比对->确认->报送
场景测试FAB文件与系统完全匹配
场景测试FAB文件与系统存在差异
场景测试部分卡报送失败后重试
场景测试全部卡报送失败后重试
场景测试空文件/格式错误文件
场景测试大批量卡(>10000)性能测试
回归测试现有 Counter 功能不受影响

14. 上线计划

gantt title 余额清空功能上线计划 dateFormat YYYY-MM-DD section 开发 数据库DDL与DAL层 :d1, 2026-04-09, 3d Domain与DomainService :d2, after d1, 3d ClearingProcessor核心逻辑 :d3, after d2, 5d CounterFacade接口实现 :d4, after d3, 3d Counter前端页面开发 :d5, after d3, 5d section 测试 单元测试 :t1, after d4, 3d 集成测试 :t2, after d5, 4d UAT测试 :t3, after t2, 5d section 上线 预发布环境验证 :r1, after t3, 2d 生产环境发布 :r2, after r1, 1d 与FAB联调 :r3, after r2, 3d 正式执行余额清空 :milestone, after r3, 0d

15. 风险评估

风险影响缓解措施
FAB 余额文件时间与系统截止时间不一致比对结果不可信与 FAB 明确约定同一时间点,双方确认后再执行
大量卡状态异常导致报送失败清空进度缓慢提前与 FAB 沟通批量修复卡状态的 SLA
FAB 接口限流报送速度受限配置合理的报送间隔和批次大小
截止时间后仍有交易余额不一致系统配置开关,截止后阻断新交易
长时间运行导致系统异常部分交易丢失支持断点续传,已成功的不重复处理
FAB
评论区
暂无评论
avatar