# 提现审核 — 技术方案

> **依据：** 《提现审核功能需求.md》v1.0、《提现管理功能需求.md》v1.0、《资金概览功能需求.md》v1.0  
> **关联：** 《关联需求分析.md》v1.6；《账户管理功能需求-草稿》；《商家端店铺上下文接口说明》；商家《全部订单技术方案》  
> **范围：** 平台端 **财务管理 · 提现审核**（列表、检索、通过/驳回）；商家端 **提现管理**（提交、记录）；共享 **店铺钱包 / 资金流水 / 收款账户 / 提现单**；**订单确认收货** 写 **订单收支**。  
> **原则：** 商家 `X-Shop-Id` 隔离；平台 **全平台** 可见；审核 **乐观锁** 状态校验；流水与余额 **同事务**。

---

## 1. 技术架构

| 项 | 选型 |
|----|------|
| 基础框架 | RuoYi **v3.9.2**（`springboot2` 分支） |
| 数据库 | **MySQL 5.7.39**；新建 **`biz_shop_wallet`**、**`biz_shop_fund_log`**、**`biz_shop_pay_account`**、**`biz_shop_withdraw`** |
| ORM / 权限 | MyBatis；`@PreAuthorize`；`AjaxResult` / `TableDataInfo` |
| 店铺上下文 | 商家 **`SellerShopContext` + `X-Shop-Id`** |
| 金额 | `BigDecimal`；**两位小数**；`ROUND_HALF_UP` |
| 编号 | 提现 **`WD` + yyyyMMdd + 6 位序号** |

### 1.1 模块边界

| 维度 | 商家 · 提现管理 | **平台 · 提现审核** | 商家 · 资金概览 |
|------|-----------------|---------------------|-----------------|
| 路径 | **`/agri/seller/finance/withdraw`** | **`/agri/finance/withdrawAudit`** | **`/agri/seller/finance/overview`**（另建） |
| 写 | **POST submit** | **PUT approve/reject** | **无** |
| 读 | 按 **shop_id** | **全平台** | 按 **shop_id** |
| 账户 | 引用 **`biz_shop_pay_account`** | 读 **快照** | 统计银行卡数 |

### 1.2 资金协作链

```text
【订单】confirmReceive → IShopFundService.settleOrder(order)
    → 订单收支流水；wallet.available += payAmount

【商家】POST /withdraw/submit
    → biz_shop_withdraw INSERT（status=1 待审核）
    → 余额提现流水；available -= amount；frozen += amount

【平台】PUT /withdrawAudit/approve/{id}
    → status=3 提现完成；提现完成流水；frozen -= amount

【平台】PUT /withdrawAudit/reject
    → status=2 审核不通过；提现驳回流水；available += amount；frozen -= amount
```

### 1.3 模块落位

```text
finance/
├── constant/FinanceConstants.java
├── support/FinanceSupport.java              # 编号、脱敏、文案
├── domain/
│   ├── BizShopWallet.java
│   ├── BizShopFundLog.java
│   ├── BizShopPayAccount.java
│   └── BizShopWithdraw.java
├── mapper/ + resources/mapper/finance/*.xml
├── service/
│   ├── IShopWalletService.java             # 钱包读写、待结算汇总
│   ├── IShopFundService.java               # 流水写入、订单结算
│   ├── IShopPayAccountService.java         # 商家账户 CRUD（提现依赖）
│   ├── ISellerWithdrawService.java
│   └── IPlatformWithdrawAuditService.java
├── controller/
│   ├── SellerWithdrawController.java
│   ├── SellerPayAccountController.java     # 账户管理最小集
│   ├── SellerFundOverviewController.java   # 资金概览只读
│   └── PlatformWithdrawAuditController.java
├── dto/ + vo/

order/service/impl/OrderAppServiceImpl.java  # confirmReceive 钩子

sql/biz_shop_finance.sql
sql/biz_shop_finance_menu.sql
```

---

## 2. 数据库设计

### 2.1 店铺钱包 `biz_shop_wallet`

| 字段 | 类型 | 说明 |
|------|------|------|
| wallet_id | bigint PK | |
| shop_id | bigint UK | 一店一行 |
| available_balance | decimal(12,2) | 可用余额 |
| frozen_amount | decimal(12,2) | 冻结金额 |
| update_time | datetime | |

> **待结算** **不落库**，运行时 `SUM(biz_order.pay_amount)` WHERE status IN (1,2) AND pay_status=1。

### 2.2 资金流水 `biz_shop_fund_log`

| 字段 | 类型 | 说明 |
|------|------|------|
| log_id | bigint PK | |
| shop_id | bigint | |
| shop_name | varchar(100) | 快照 |
| biz_no | varchar(32) | 订单号/提现编号 |
| change_reason | char(1) | `1`订单收支 `2`余额提现 `3`提现驳回 `4`提现完成 |
| balance_change | decimal(12,2) | 余额变动（可负） |
| balance_after | decimal(12,2) | 变动后余额 |
| frozen_change | decimal(12,2) | 冻结变动 |
| frozen_after | decimal(12,2) | 变动后冻结 |
| ref_type | varchar(16) | ORDER / WITHDRAW |
| ref_id | bigint | |
| create_time | datetime | 变动时间 |

**索引：** `idx_shop_time (shop_id, create_time)`。

### 2.3 收款账户 `biz_shop_pay_account`

| 字段 | 类型 | 说明 |
|------|------|------|
| account_id | bigint PK | |
| shop_id | bigint | |
| account_type | char(1) | `1`银行卡 `2`支付宝 `3`微信 |
| real_name | varchar(64) | |
| account_no | varchar(128) | 明文存储；展示脱敏 |
| del_flag | char(1) | `0`正常 `2`删除 |
| create_time / update_time | datetime | |

**索引：** `idx_shop_del (shop_id, del_flag)`。

### 2.4 提现单 `biz_shop_withdraw`

| 字段 | 类型 | 说明 |
|------|------|------|
| withdraw_id | bigint PK | |
| withdraw_no | varchar(32) UK | WDyyyyMMdd###### |
| shop_id | bigint | |
| shop_name | varchar(100) | 列表快照 |
| account_id | bigint | 原账户 ID |
| account_type | char(1) | 快照 |
| account_real_name | varchar(64) | 快照 |
| account_no_mask | varchar(128) | 快照脱敏 |
| withdraw_amount | decimal(12,2) | |
| remark | varchar(200) | 商家备注 |
| withdraw_status | char(1) | `1`待审核 `2`审核不通过 `3`提现完成 |
| process_remark | varchar(200) | 平台处理说明 |
| audit_by | varchar(64) | |
| audit_time | datetime | |
| apply_time | datetime | 申请时间 |
| create_by | varchar(64) | |

**索引：** `idx_shop_status_time (shop_id, withdraw_status, apply_time)`、`idx_status_time (withdraw_status, apply_time)`。

---

## 3. 接口设计

### 3.1 商家 · 提现管理

**基路径：** `/agri/seller/finance/withdraw`  
**上下文：** `X-Shop-Id`

| 方法 | 路径 | 权限 | 说明 |
|------|------|------|------|
| GET | `/list` | `agri:seller:finance:withdraw:list` | 提现记录 |
| GET | `/balance` | `agri:seller:finance:withdraw:list` | 可用余额（提交页辅助） |
| POST | `/submit` | `agri:seller:finance:withdraw:submit` | 提交提现 |

**Query（SellerWithdrawQuery）：** pageNum, pageSize, beginApplyTime, endApplyTime, withdrawStatus

**Body（SellerWithdrawSubmitDTO）：** accountId, withdrawAmount, remark

**POST 成功 data：** withdrawId, withdrawNo, withdrawStatus

### 3.2 商家 · 账户管理（提现依赖）

**基路径：** `/agri/seller/finance/payAccount`

| 方法 | 路径 | 权限 | 说明 |
|------|------|------|------|
| GET | `/list` | `agri:seller:finance:payAccount:list` | 全部账户 |
| GET | `/options` | `agri:seller:finance:withdraw:list` | 提现下拉 |
| POST | `/` | `agri:seller:finance:payAccount:add` | 添加 |
| PUT | `/` | `agri:seller:finance:payAccount:edit` | 编辑 |
| DELETE | `/{accountId}` | `agri:seller:finance:payAccount:remove` | 删除 |

### 3.3 商家 · 资金概览（只读）

**基路径：** `/agri/seller/finance/overview`

| 方法 | 路径 | 权限 | 说明 |
|------|------|------|------|
| GET | `/summary` | `agri:seller:finance:overview:query` | 四块概览 |
| GET | `/logs` | `agri:seller:finance:overview:query` | 收支流水 |

### 3.4 平台 · 提现审核

**基路径：** `/agri/finance/withdrawAudit`

| 方法 | 路径 | 权限 | 说明 |
|------|------|------|------|
| GET | `/list` | `agri:finance:withdrawAudit:list` | 全平台列表 |
| GET | `/pendingCount` | `agri:finance:withdrawAudit:list` | 待审数量 |
| PUT | `/approve/{withdrawId}` | `agri:finance:withdrawAudit:audit` | 审核通过 |
| PUT | `/reject` | `agri:finance:withdrawAudit:audit` | 审核驳回 |

**Query（PlatformWithdrawAuditQuery）：** pageNum, pageSize, beginApplyTime, endApplyTime, withdrawStatus

**Body（WithdrawAuditDTO）：** withdrawId（reject 时）, processRemark（必填，≤200）

---

## 4. 业务规则（实现）

| 编号 | 规则 |
|------|------|
| FIN1 | `selectWalletForUpdate(shopId)` + 事务 |
| FIN2 | 提交：`amount > 0` 且 `amount <= available` |
| FIN3 | 提交：写 withdraw + 余额提现流水 + 更新 wallet |
| FIN4 | 审核：`updateStatusIfPending(id, old=1, new)` 行数=0 → 状态已变更 |
| FIN5 | 通过/驳回：`processRemark` 非空且 ≤200 |
| FIN6 | 驳回：available+=amount, frozen-=amount, 提现驳回流水 |
| FIN7 | 通过：frozen-=amount, 提现完成流水 |
| FIN8 | 订单结算：幂等 `countFundLogByOrder(orderId)` >0 则跳过 |
| FIN9 | 账户快照：提交时 copy type/name/mask |
| FIN10 | 编号：`FinanceSupport.nextWithdrawNo()` |

---

## 5. 权限与菜单

| 菜单 | menu_id | path | 权限前缀 |
|------|---------|------|----------|
| 财务中心（商家） | 6600 | finance | — |
| 资金概览 | 6610 | overview | `agri:seller:finance:overview` |
| 提现管理 | 6620 | withdraw | `agri:seller:finance:withdraw` |
| 账户管理 | 6630 | payAccount | `agri:seller:finance:payAccount` |
| 财务管理（平台） | 7600 | finance | — |
| 提现审核 | 7610 | withdrawAudit | `agri:finance:withdrawAudit` |

脚本：`sql/biz_shop_finance_menu.sql`。

---

## 6. 实现清单

| # | 项 | 状态 |
|---|-----|------|
| 1 | DDL `sql/biz_shop_finance.sql` | 待执行 |
| 2 | Domain / Mapper / XML | 待建 |
| 3 | FinanceConstants / FinanceSupport | 待建 |
| 4 | ShopFundService（流水+钱包+结算） | 待建 |
| 5 | SellerWithdraw + PlatformWithdrawAudit | 待建 |
| 6 | SellerPayAccount + SellerFundOverview | 待建 |
| 7 | OrderAppServiceImpl 钩子 | 待建 |
| 8 | 菜单 SQL + 单元测试 | 待建 |

---

## 7. 版本记录

| 版本 | 说明 |
|------|------|
| **v1.0** | 首版：对齐提现审核/提现管理/资金概览需求 v1.0；钱包+流水+提现+账户+订单结算 |

---

*文档版本：v1.0 · 依据《提现审核功能需求.md》v1.0、《提现管理功能需求.md》v1.0*
