docs(finance): define credit and wallet hold contract
This commit is contained in:
+1
-1
@@ -47,7 +47,7 @@
|
||||
|
||||
| 工作包 | 执行任务 | 写入范围 | 交付目标 | 依赖与集成边界 |
|
||||
|---|---|---|---|---|
|
||||
| `WALLET-BE-FINANCE` | 【开发总控】全流程开发 | `baiyue-firstleg/finance/`、Finance OpenAPI、模块 SQL 与统一增量 SQL、必要 Finance/File 内部客户端 | 新增客户资金账户、充值申请和资金流水主账;提供客户账户/流水/充值申请接口及平台账户列表/详情、待审充值、审核、手工充值/扣款接口;实现客户隔离、金额校验、权限、幂等、乐观并发与测试 | Finance 拥有余额和流水;付款截图经 Finance 调用 File 内部 `FINANCE_VOUCHER` 保存;不接支付回调、不接订单消费 |
|
||||
| `WALLET-BE-FINANCE` | 【开发总控】全流程开发 | `baiyue-firstleg/finance/`、Finance OpenAPI、模块 SQL 与统一增量 SQL、必要 Finance/File 内部客户端 | 新增客户资金账户、充值申请、授信额度、资金冻结和流水主账;提供客户账户/流水/充值申请接口及平台账户列表/详情、待审充值、审核、手工充值/扣款/授信接口,并提供业务模块使用的冻结、结算和释放内部接口;实现客户隔离、金额校验、权限、服务令牌、幂等、乐观并发与测试 | Finance 拥有余额、授信、冻结和流水;扣款先使用实际资金再使用授信,充值先归还已用授信;付款截图经 Finance 调用 File 内部 `FINANCE_VOUCHER` 保存;不接第三方支付回调,具体一件代发业务调用后续接线 |
|
||||
| `WALLET-FE-CLIENT` | 【开发全流程前端】Client | `apps/client-web/src/modules/finance/` 及该模块路由、导航和测试 | 新增客户资金账户页,显示实际/冻结/可用余额和流水;按原型完成金额选择、微信/支付宝静态二维码、付款截图上传、提交待审核及状态反馈 | 客户范围只取登录态;只调用 `/api/client/finance/v1/**`,无二维码配置时明确不可提交,不模拟支付成功 |
|
||||
| `WALLET-FE-ADMIN` | 【开发全流程前端】Admin | `apps/admin-web/src/modules/finance/` 及对应测试 | 将客户账户页收敛为三余额账户;详情中待审核客户充值置顶并提供审核,保留流水;列表/详情提供手工充值和手工扣款,操作列固定首列 | 只消费 Finance 正式 API;审核、充值、扣款分别受写权限控制;不在前端计算或兜底余额 |
|
||||
| `WALLET-BE-IAM` | 【开发全流程后端】IAM权限 | `baiyue-firstleg/iam/` 及必要权限初始化 SQL、OpenAPI 和测试 | 新增并初始化客户账户查看/充值申请和平台充值审核/账户调账权限,保持列表只读与写操作分离 | 企业负责人默认获得客户账户查看和充值申请权限;平台财务角色按现有初始化规则获得审核与调账权限,不修改 Finance 业务 |
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
|
||||
## 当前确认:一件代发客户资金账户(2026-09-05)
|
||||
|
||||
当前对话已将资金账户作为一件代发的前置节点重新纳入范围,并覆盖本文后续历史章节中“钱包不做”的旧结论。首批固定为 CNY,满足 `实际余额 = 冻结金额 + 可用余额`;冻结金额本批只持久化和展示,暂不接消费。
|
||||
当前对话已将资金账户作为一件代发的前置节点重新纳入范围,并覆盖本文后续历史章节中“钱包不做”的旧结论。首批固定为 CNY。账户分别保存实际余额、冻结金额、授信额度、已用授信和冻结授信;`总可用余额 = 实际余额 + 授信额度 - 已用授信 - 冻结金额`,`可用授信 = 授信额度 - 已用授信 - 冻结授信`。扣款及业务冻结先使用未冻结的实际资金,再使用授信;充值先归还已用授信,剩余金额增加实际余额。
|
||||
|
||||
客户选择固定或自定义金额,查看后台配置的微信/支付宝静态收款码,付款后上传 JPG/PNG 截图形成待审核申请。平台在客户账户明细顶部审核或驳回,也可手工充值、扣款;每次变动写不可变账户流水。审核、账户更新、流水和幂等结果在 Finance 单事务内完成,文件内容仍归 File 服务。接口契约见 [客户资金账户 OpenAPI](openapi/finance-wallet-v1.yaml)。
|
||||
客户选择固定或自定义金额,查看后台配置的微信/支付宝静态收款码,付款后上传 JPG/PNG 截图形成待审核申请。平台在客户账户明细顶部审核或驳回,也可手工充值、扣款和设置客户授信额度;每次变动写不可变账户流水。新账户授信额度读取 `baiyue.finance.wallet.default-credit-limit`,默认 `0.00`,平台设置的客户额度随后独立持久化。Finance 还提供仅服务令牌可访问、按业务类型和业务单号幂等的冻结、结算和释放接口,供一件代发等模块接入。审核、账户更新、流水、冻结记录和幂等结果在 Finance 单事务内完成,文件内容仍归 File 服务。接口契约见 [客户资金账户 OpenAPI](openapi/finance-wallet-v1.yaml)。
|
||||
|
||||
> 盘点日期:2026-08-10
|
||||
> 当前状态:F0/F1 已有 Finance 服务、数据库、权限、Admin/Client 页面和基础接口;订单与客户 11 个 P0 operation 的目标契约已冻结,本地实现验收按独立 G1-G4 证据矩阵均为 `PASS`;真实 MySQL、测试环境 HTTP 冒烟和领导页面验收仍需单独执行
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: 客户资金账户与充值 API
|
||||
version: 1.0.0
|
||||
description: 静态收款码、付款截图申请、平台审核及手工充值扣款。当前币种固定 CNY,消费暂不接入。
|
||||
title: 客户资金账户、授信与充值 API
|
||||
version: 1.1.0
|
||||
description: |
|
||||
CNY 资金账户支持静态收款码、付款截图申请、平台审核、手工充扣、授信额度及业务冻结/结算/释放。
|
||||
总可用余额 = 实际余额 + 授信额度 - 已用授信 - 冻结金额;业务扣款先使用未冻结的实际资金,再使用授信。
|
||||
充值先归还已用授信,剩余部分增加实际余额。新账户授信额度由
|
||||
`baiyue.finance.wallet.default-credit-limit` 初始化,默认 `0.00`,平台可按客户调整。
|
||||
paths:
|
||||
/api/client/finance/v1/account:
|
||||
get:
|
||||
summary: 查询当前客户资金账户
|
||||
responses:
|
||||
'200': { description: 成功 }
|
||||
'200':
|
||||
description: 成功
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/WalletAccountEnvelope' }
|
||||
/api/client/finance/v1/account/ledger:
|
||||
get:
|
||||
summary: 查询当前客户账户流水
|
||||
@@ -91,6 +99,71 @@ paths:
|
||||
schema: { $ref: '#/components/schemas/AccountAdjustmentRequest' }
|
||||
responses:
|
||||
'200': { description: 成功 }
|
||||
/api/platform/finance/v1/accounts/{customerId}/credit-limit:
|
||||
put:
|
||||
summary: 设置客户授信额度
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
- $ref: '#/components/parameters/IdempotencyKey'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CreditLimitRequest' }
|
||||
responses:
|
||||
'200': { description: 成功并生成授信调整流水 }
|
||||
/internal/finance/v1/wallet/accounts/{customerId}:
|
||||
get:
|
||||
summary: 业务模块查询客户资金账户
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/InternalServiceToken'
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
responses:
|
||||
'200': { description: 成功 }
|
||||
/internal/finance/v1/wallet/accounts/{customerId}/holds:
|
||||
post:
|
||||
summary: 按业务单冻结资金,先冻结实际资金再冻结授信
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/InternalServiceToken'
|
||||
- $ref: '#/components/parameters/IdempotencyKey'
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/WalletFreezeRequest' }
|
||||
responses:
|
||||
'200': { description: 成功;同一客户、业务类型和业务单号只允许一条冻结记录 }
|
||||
/internal/finance/v1/wallet/accounts/{customerId}/holds/{businessType}/{businessNo}/settle:
|
||||
post:
|
||||
summary: 结算已冻结资金
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/InternalServiceToken'
|
||||
- $ref: '#/components/parameters/IdempotencyKey'
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
- $ref: '#/components/parameters/BusinessType'
|
||||
- $ref: '#/components/parameters/BusinessNo'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/WalletHoldActionRequest' }
|
||||
responses:
|
||||
'200': { description: 成功;实际冻结转为实际扣减,授信冻结转为已用授信 }
|
||||
/internal/finance/v1/wallet/accounts/{customerId}/holds/{businessType}/{businessNo}/release:
|
||||
post:
|
||||
summary: 释放已冻结资金
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/InternalServiceToken'
|
||||
- $ref: '#/components/parameters/IdempotencyKey'
|
||||
- $ref: '#/components/parameters/CustomerId'
|
||||
- $ref: '#/components/parameters/BusinessType'
|
||||
- $ref: '#/components/parameters/BusinessNo'
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/WalletHoldActionRequest' }
|
||||
responses:
|
||||
'200': { description: 成功;实际资金和授信恢复为可用 }
|
||||
components:
|
||||
parameters:
|
||||
IdempotencyKey:
|
||||
@@ -98,6 +171,11 @@ components:
|
||||
in: header
|
||||
required: true
|
||||
schema: { type: string, maxLength: 128 }
|
||||
InternalServiceToken:
|
||||
name: X-Internal-Service-Token
|
||||
in: header
|
||||
required: true
|
||||
schema: { type: string, writeOnly: true }
|
||||
CustomerId:
|
||||
name: customerId
|
||||
in: path
|
||||
@@ -108,7 +186,35 @@ components:
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, pattern: '^[1-9][0-9]*$' }
|
||||
BusinessType:
|
||||
name: businessType
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, pattern: '^[A-Z][A-Z0-9_]{1,31}$' }
|
||||
BusinessNo:
|
||||
name: businessNo
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, minLength: 1, maxLength: 128 }
|
||||
schemas:
|
||||
WalletAccountEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data: { $ref: '#/components/schemas/WalletAccount' }
|
||||
WalletAccount:
|
||||
type: object
|
||||
required: [currencyCode, actualBalance, frozenBalance, availableBalance, creditLimit, creditUsed, creditFrozen, availableCredit, version]
|
||||
properties:
|
||||
currencyCode: { type: string, enum: [CNY] }
|
||||
actualBalance: { type: number, format: decimal, minimum: 0 }
|
||||
frozenBalance: { type: number, format: decimal, minimum: 0, description: 实际资金冻结与授信冻结合计 }
|
||||
availableBalance: { type: number, format: decimal, minimum: 0, description: 实际可用资金与可用授信合计 }
|
||||
creditLimit: { type: number, format: decimal, minimum: 0 }
|
||||
creditUsed: { type: number, format: decimal, minimum: 0 }
|
||||
creditFrozen: { type: number, format: decimal, minimum: 0 }
|
||||
availableCredit: { type: number, format: decimal, minimum: 0 }
|
||||
version: { type: integer, minimum: 0 }
|
||||
updatedAt: { type: string, format: date-time, nullable: true }
|
||||
RechargeReviewRequest:
|
||||
type: object
|
||||
required: [decision, expectedVersion]
|
||||
@@ -127,3 +233,22 @@ components:
|
||||
referenceNo: { type: string, maxLength: 128 }
|
||||
remark: { type: string, maxLength: 500 }
|
||||
expectedAccountVersion: { type: integer, minimum: 0 }
|
||||
CreditLimitRequest:
|
||||
type: object
|
||||
required: [creditLimit, expectedAccountVersion]
|
||||
properties:
|
||||
creditLimit: { type: number, format: decimal, minimum: 0 }
|
||||
remark: { type: string, maxLength: 500 }
|
||||
expectedAccountVersion: { type: integer, minimum: 0 }
|
||||
WalletFreezeRequest:
|
||||
type: object
|
||||
required: [amount, businessType, businessNo]
|
||||
properties:
|
||||
amount: { type: number, format: decimal, minimum: 0.01 }
|
||||
businessType: { type: string, minLength: 1, maxLength: 64 }
|
||||
businessNo: { type: string, minLength: 1, maxLength: 128 }
|
||||
remark: { type: string, maxLength: 500 }
|
||||
WalletHoldActionRequest:
|
||||
type: object
|
||||
properties:
|
||||
remark: { type: string, maxLength: 500 }
|
||||
|
||||
Reference in New Issue
Block a user