# 财务系统数据库表结构说明

## 数据库表与 Entity 映射关系

| 数据库表 | Entity 文件 | 说明 | 状态 |
|---------|------------|------|------|
| `user_accounts` | `user-account.entity.ts` | 用户账户表 | ✅ 已完成 |
| `merchant_accounts` | `merchant-account.entity.ts` | 商家账户表 | ✅ 已完成 |
| `platform_accounts` | `platform-account.entity.ts` | 平台账户表 | ✅ 已完成 |
| `user_transactions` | `user-transaction.entity.ts` | 用户交易流水表 | ✅ 已完成 |
| `merchant_transactions` | `merchant-transaction.entity.ts` | 商家交易流水表 | ✅ 已完成 |
| `platform_transactions` | `platform-transaction.entity.ts` | 平台交易流水表 | ✅ 已完成 |
| `user_withdrawals` | `user-withdrawal.entity.ts` | 用户提现表 | ✅ 已完成 |
| `merchant_withdrawals` | `merchant-withdrawal.entity.ts` | 商家提现表 | ✅ 已完成 |
| `platform_withdrawals` | `platform-withdrawal.entity.ts` | 平台提现表 | ✅ 已完成 |
| `settlements` | `settlement.entity.ts` | 结算单表 | ✅ 已完成 |
| `settlement_items` | `settlement-item.entity.ts` | 结算明细表 | ✅ 已完成 |
| `daily_reconciliations` | `daily-reconciliation.entity.ts` | 日对账表 | ✅ 已完成 |

## 数据库初始化说明

### 1. 迁移脚本位置

`database/migrations/001_init_schema.sql` 已包含完整的财务系统表结构（第 606-901 行）

### 2. 自动创建的数据

执行迁移脚本后会自动创建：

1. **触发器**
   - `trg_user_create_account`: 用户注册时自动创建用户账户
   - `trg_merchant_create_account`: 商家审核通过时自动创建商家账户

### 3. 表结构版本说明

⚠️ **重要**: 旧版本的 `settlements` 和 `withdrawals` 表定义已删除。

**当前使用**: 按角色分离的账户和交易表（user_accounts、merchant_accounts、platform_accounts 等）

## 字段说明

### user_accounts（用户账户表）

```sql
CREATE TABLE `user_accounts` (
  `id` BIGINT UNSIGNED AUTO_INCREMENT,
  `user_id` BIGINT UNSIGNED,                          -- 用户ID
  `balance` DECIMAL(12,2) DEFAULT 0.00,               -- 可用余额
  `frozen_balance` DECIMAL(12,2) DEFAULT 0.00,        -- 冻结余额（提现中）
  `total_income` DECIMAL(12,2) DEFAULT 0.00,          -- 累计收入（邀请返现）
  `total_expense` DECIMAL(12,2) DEFAULT 0.00,         -- 累计支出（提现）
  `version` INT UNSIGNED DEFAULT 0,                   -- 乐观锁版本号
  `status` ENUM('active','frozen','closed'),          -- 状态
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_id` (`user_id`)
);
```

### merchant_accounts（商家账户表）

```sql
CREATE TABLE `merchant_accounts` (
  `id` BIGINT UNSIGNED AUTO_INCREMENT,
  `merchant_id` BIGINT UNSIGNED,                      -- 商家ID
  `balance` DECIMAL(12,2) DEFAULT 0.00,               -- 可用余额
  `frozen_balance` DECIMAL(12,2) DEFAULT 0.00,        -- 冻结余额（提现中）
  `debt_amount` DECIMAL(12,2) DEFAULT 0.00,           -- 欠款金额（退款扣回）
  `total_income` DECIMAL(12,2) DEFAULT 0.00,          -- 累计收入（订单结算）
  `total_expense` DECIMAL(12,2) DEFAULT 0.00,         -- 累计支出（提现+退款扣回）
  `total_settlement` DECIMAL(12,2) DEFAULT 0.00,      -- 累计结算金额
  `total_withdraw` DECIMAL(12,2) DEFAULT 0.00,        -- 累计提现金额
  `last_settlement_at` DATETIME,                      -- 最后结算时间
  `pending_settlement` DECIMAL(12,2) DEFAULT 0.00,    -- 待结算金额
  `version` INT UNSIGNED DEFAULT 0,                   -- 乐观锁版本号
  `status` ENUM('active','frozen','closed'),          -- 状态
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_merchant_id` (`merchant_id`)
);
```

### platform_accounts（平台账户表）

```sql
CREATE TABLE `platform_accounts` (
  `id` BIGINT UNSIGNED AUTO_INCREMENT,
  `account_name` VARCHAR(50),                         -- 账户名称
  `balance` DECIMAL(12,2) DEFAULT 0.00,               -- 可用余额
  `frozen_balance` DECIMAL(12,2) DEFAULT 0.00,        -- 冻结余额
  `total_income` DECIMAL(12,2) DEFAULT 0.00,          -- 累计收入（订单收入）
  `total_expense` DECIMAL(12,2) DEFAULT 0.00,         -- 累计支出（商家结算+退款）
  `total_service_fee` DECIMAL(12,2) DEFAULT 0.00,     -- 累计服务费收入
  `version` INT UNSIGNED DEFAULT 0,                   -- 乐观锁版本号
  `status` ENUM('active','frozen','closed'),          -- 状态
  PRIMARY KEY (`id`)
);
```

**关键点**:
- 账户按角色分离：用户、商家、平台各有独立的账户表
- 每个账户表都有 `version` 字段用于乐观锁，防止并发问题
- `balance` 和 `frozen_balance` 有 CHECK 约束，不能为负数

### user_transactions / merchant_transactions / platform_transactions（交易流水表）

交易流水表也按角色分离，结构类似：

```sql
CREATE TABLE `user_transactions` (
  `id` BIGINT UNSIGNED AUTO_INCREMENT,
  `transaction_no` VARCHAR(32) UNIQUE,                -- 交易流水号（全局唯一）
  `user_id` BIGINT UNSIGNED,                          -- 用户ID
  `account_id` BIGINT UNSIGNED,                       -- 用户账户ID
  `direction` ENUM('income','expense'),               -- 方向
  `amount` DECIMAL(12,2),                             -- 金额
  `balance_before` DECIMAL(12,2),                     -- 交易前余额
  `balance_after` DECIMAL(12,2),                      -- 交易后余额
  `transaction_type` VARCHAR(50),                     -- 交易类型
  `business_type` VARCHAR(50),                        -- 业务类型
  `business_id` BIGINT UNSIGNED,                      -- 业务ID
  `business_no` VARCHAR(32),                          -- 业务单号
  `related_account_type` ENUM('platform','merchant'), -- 对方账户类型
  `related_account_id` BIGINT UNSIGNED,               -- 对方账户ID
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_transaction_no` (`transaction_no`)
);
```

**关键点**:
- 复式记账：每笔转账生成两条流水（一条支出 + 一条收入）
- `transaction_no` 相同的两条流水表示同一笔转账
- `related_account_type` 和 `related_account_id` 关联对方账户

### settlements（结算单表）

```sql
CREATE TABLE `settlements` (
  `id` BIGINT UNSIGNED AUTO_INCREMENT,
  `settlement_no` VARCHAR(32) UNIQUE,                 -- 结算单号
  `merchant_id` BIGINT UNSIGNED,                      -- 商家ID
  `period_start` DATE,                                -- 周期开始
  `period_end` DATE,                                  -- 周期结束
  `order_count` INT UNSIGNED DEFAULT 0,               -- 订单数量
  `order_amount` DECIMAL(12,2) DEFAULT 0.00,          -- 订单总额
  `service_fee` DECIMAL(12,2) DEFAULT 0.00,           -- 服务费
  `settlement_amount` DECIMAL(12,2) DEFAULT 0.00,     -- 结算金额
  `status` ENUM('pending','settled','failed'),        -- 状态
  `settled_at` DATETIME,                              -- 结算时间
  PRIMARY KEY (`id`)
);
```

**关键点**:
- 每周一凌晨2点自动生成上周的结算单
- `settlement_amount` = `order_amount` - `service_fee`
- 结算时执行转账：平台账户 → 商家账户

### daily_reconciliations（日对账表）

```sql
CREATE TABLE `daily_reconciliations` (
  `id` BIGINT UNSIGNED AUTO_INCREMENT,
  `reconciliation_date` DATE UNIQUE,                  -- 对账日期
  `platform_balance` DECIMAL(12,2),                   -- 平台余额
  `merchant_balance_sum` DECIMAL(12,2),               -- 商家余额总和
  `user_balance_sum` DECIMAL(12,2),                   -- 用户余额总和
  `total_balance` DECIMAL(12,2),                      -- 总余额
  `order_income` DECIMAL(12,2) DEFAULT 0.00,          -- 订单收入
  `service_fee` DECIMAL(12,2) DEFAULT 0.00,           -- 服务费
  `merchant_settlement` DECIMAL(12,2) DEFAULT 0.00,   -- 商家结算
  `cashback_expense` DECIMAL(12,2) DEFAULT 0.00,      -- 返现支出
  `withdraw_expense` DECIMAL(12,2) DEFAULT 0.00,      -- 提现支出
  `refund_expense` DECIMAL(12,2) DEFAULT 0.00,        -- 退款支出
  `status` ENUM('balanced','unbalanced'),             -- 状态
  `error_message` TEXT,                               -- 异常信息
  PRIMARY KEY (`id`)
);
```

**关键点**:
- 每天凌晨3点自动执行对账
- 检查借贷平衡：收入总额 = 支出总额
- 如有异常记录 `error_message` 并发送告警

## 业务流程与数据库操作

### 1. 用户支付订单

```
1. 用户支付 → 平台账户收入
2. 插入 transactions 记录（平台账户 income）
3. 更新 accounts.balance（平台账户）
```

### 2. 周结算

```
1. 查询上周已完成订单
2. 按商家分组计算结算金额
3. 插入 settlements 记录
4. 插入 settlement_items 记录（订单明细）
5. 执行转账：平台账户 → 商家账户
   - 插入 2 条 transactions 记录（复式记账）
   - 更新 2 个 accounts.balance
```

### 3. 商家提现

```
1. 商家申请提现
   - 插入 merchant_withdrawals 记录
   - 冻结商家账户余额（frozen_balance += amount）
2. 管理员审核通过
   - 更新 merchant_withdrawals.status = 'approved'
3. 管理员确认打款
   - 扣减余额（balance -= amount, frozen_balance -= amount）
   - 插入 transactions 记录（商家账户 expense）
   - 更新 merchant_withdrawals.status = 'paid'
```

### 4. 日对账

```
1. 统计各账户余额
   - SELECT SUM(balance) FROM accounts WHERE account_type = 'platform'
   - SELECT SUM(balance) FROM accounts WHERE account_type = 'merchant'
   - SELECT SUM(balance) FROM accounts WHERE account_type = 'user'
2. 统计当日交易金额
   - SELECT SUM(amount) FROM transactions WHERE direction = 'income'
   - SELECT SUM(amount) FROM transactions WHERE direction = 'expense'
3. 检查借贷平衡
   - 收入总额 = 支出总额（允许 0.01 元误差）
4. 插入 daily_reconciliations 记录
```

## 索引说明

### 关键索引

1. **accounts 表**
   - `uk_type_owner`: 唯一索引，确保每个用户/商家只有一个账户
   - `idx_status`: 按状态查询

2. **transactions 表**
   - `uk_transaction_no`: 唯一索引，防止重复交易
   - `idx_account_id`: 按账户查询流水
   - `idx_business`: 按业务类型和业务ID查询
   - `idx_created_at`: 按时间范围查询

3. **settlements 表**
   - `uk_settlement_no`: 唯一索引
   - `idx_merchant_id`: 按商家查询
   - `idx_period`: 按周期查询

4. **withdrawals 表**
   - `uk_withdraw_no`: 唯一索引
   - `idx_status`: 按状态查询（待审核、已打款等）

## 数据一致性保证

### 1. 事务保证

所有涉及金额变动的操作都在事务中执行：
- 转账操作（账户余额变动 + 交易流水插入）
- 提现操作（余额冻结/扣减 + 提现记录更新）
- 结算操作（结算单生成 + 转账执行）

### 2. 乐观锁

`accounts` 表使用 `version` 字段实现乐观锁，防止并发更新导致余额错误。

### 3. CHECK 约束

```sql
CONSTRAINT `chk_balance` CHECK (`balance` >= 0)
CONSTRAINT `chk_frozen_balance` CHECK (`frozen_balance` >= 0)
```

确保余额不会为负数。

### 4. 触发器

- 用户注册时自动创建账户
- 商家审核通过时自动创建账户

## 下一步工作

1. ✅ 数据库表结构已完成
2. ✅ Entity 层已完成
3. ✅ Service 层已完成
4. ✅ Controller 层已完成
5. ✅ DTO 层已完成
6. ⏳ 执行数据库迁移脚本
7. ⏳ 集成到订单模块（订单支付时调用账户服务）
8. ⏳ 编写单元测试
9. ⏳ 前端页面开发

## 注意事项

1. **删除旧版 settlements 表定义**: 数据库脚本中第 394-417 行的旧版本定义应该删除，避免混淆。

2. **执行迁移脚本**: 确保按顺序执行 `001_init_schema.sql`，会自动创建所有表和触发器。

3. **平台账户**: 迁移脚本会自动创建平台账户（`owner_id=0`），无需手动创建。

4. **定时任务**: 需要在 NestJS 中启用 `@nestjs/schedule` 模块，定时任务才会执行。
