# 财务系统设计文档

> **版本**：v3.0（合并版）  
> **最后更新**：2024-01-XX  
> **状态**：✅ 已实现并优化

---

## 📋 目录

1. [概述](#概述)
2. [账户体系](#账户体系)
3. [资金流转](#资金流转)
4. [结算周期](#结算周期)
5. [服务费计算](#服务费计算)
6. [核心服务](#核心服务)
7. [数据库表结构](#数据库表结构)
8. [前端展示](#前端展示)
9. [API接口](#api接口)
10. [扩展方案](#扩展方案)
11. [安全保障](#安全保障)
12. [数据一致性保证](#数据一致性保证)
13. [测试验证](#测试验证)
14. [部署说明](#部署说明)
15. [常见问题](#常见问题)
16. [更新日志](#更新日志)

---

## 概述

本文档描述了租房平台的财务系统架构，包括账户体系、资金流转、结算逻辑和安全保障机制。

**核心特性**：
- ✅ 四层账户体系（系统总账户、平台账户、商家账户、用户账户）
- ✅ 资金守恒验证机制
- ✅ 订单支付、结算、退款、提现完整流程
- ✅ 自动周结算（每周一凌晨2点）
- ✅ 邀请返现机制
- ✅ 多重安全保障（事务、悲观锁、乐观锁、复式记账）
- ✅ 完整的交易流水记录

---

## 账户体系

### 账户名称常量说明

为了提高代码可维护性和国际化支持，系统账户名称采用英文常量存储，前端显示时映射为中文。

**账户名称映射表：**

| 英文常量 (数据库存储) | 中文显示名称 | 说明 |
|---------------------|------------|------|
| `SYSTEM_MAIN` | 系统总账户 | 记录整个系统的资金流入流出，用于资金守恒验证 |
| `PLATFORM_MAIN` | 平台主账户 | 平台的主要收益账户，记录服务费收入和邀请返现支出 |
| `PLATFORM_BACKUP` | 平台备用账户 | 平台的备用账户（可选） |

**后端使用：**
```typescript
// 导入常量
import { ACCOUNT_NAMES } from '@/constants/account.constant';

// 使用常量查询
const systemAccount = await this.systemAccountRepo.findOne({
  where: { account_name: ACCOUNT_NAMES.SYSTEM_MAIN }
});

const platformAccount = await this.platformAccountRepo.findOne({
  where: { account_name: ACCOUNT_NAMES.PLATFORM_MAIN }
});
```

**前端使用：**
```typescript
// 导入映射工具
import { getAccountDisplayName } from '@/utils/accountNameMap';

// 将英文常量转换为中文显示
const displayName = getAccountDisplayName('SYSTEM_MAIN'); // 返回：系统总账户
const displayName2 = getAccountDisplayName('PLATFORM_MAIN'); // 返回：平台主账户
```

### 四层账户结构

系统采用四层账户结构，确保资金流转清晰、职责明确：

#### 1. 系统总账户 (System Account)

**职责**：记录平台内所有未提现的资金总额

**计算公式**：
```
系统总账户余额 = 用户实付总额 - 累计退款 - 累计提现
```

**字段说明**：
- `balance`: 当前余额
- `total_income`: 累计收入（用户实付总额）
- `total_refund`: 累计退款
- `total_withdrawn`: 累计提现

**数据表**：`system_accounts`

#### 2. 平台账户 (Platform Account)

**职责**：记录平台净收益（服务费收入 - 邀请返现支出）

**计算公式**：
```
平台账户余额 = 累计服务费收入 - 累计邀请返现支出
```

**字段说明**：
- `balance`: 当前余额
- `total_income`: 累计收入（服务费收入）
- `total_expense`: 累计支出（邀请返现支出）

**数据表**：`platform_accounts`

#### 3. 商家账户 (Merchant Account)

**职责**：记录商家的订单收入和提现

**计算公式**：
```
商家账户余额 = 累计订单收入 - 累计提现
订单收入 = 订单金额 - 服务费
```

**字段说明**：
- `balance`: 可用余额
- `frozen_balance`: 冻结余额（提现申请中）
- `total_income`: 累计收入
- `total_expense`: 累计支出（提现）

**数据表**：`merchant_accounts`

#### 4. 用户账户 (User Account)

**职责**：记录用户的邀请返现收入和提现

**计算公式**：
```
用户账户余额 = 累计邀请返现 - 累计提现
```

**字段说明**：
- `balance`: 可用余额
- `frozen_balance`: 冻结余额（提现申请中）
- `total_income`: 累计收入（邀请返现）
- `total_expense`: 累计支出（提现）

**数据表**：`user_accounts`

### 资金守恒验证

系统通过以下公式验证资金守恒：

```
系统总账户余额 = 商家账户余额总和 + 用户账户余额总和 + 平台账户余额
```

这个公式确保平台内所有资金都有明确的归属，不会出现资金丢失或凭空产生的情况。

## 资金流转

### 1. 订单支付流程

```
用户支付订单
  ↓
系统总账户 +实付金额
  ↓
订单状态：pending_pay → pending_confirm
```

**涉及文件**：
- `apps/server/src/modules/app/order/order.service.ts` (payByOrderNo, pay 方法)
- `apps/server/src/modules/shared/finance/account.service.ts` (addSystemIncome 方法)

**关键代码**：
```typescript
// 记录系统总账户收入（用户实付金额）
await this.accountService.addSystemIncome(
  order.payAmount,
  transactionNo,
  'order_payment',
  order.id,
  order.orderNo,
  `用户支付订单：${order.orderNo}`,
);
```

### 2. 订单结算流程

```
订单完成（用户离店）
  ↓
商家账户 +（实付金额 - 服务费）
  ↓
平台账户 +服务费
  ↓
如果有邀请关系：
  用户账户（邀请人）+返现金额
  平台账户 -返现金额
```

**涉及文件**：
- `apps/server/src/modules/shared/finance/settlement.service.ts` (createSettlement 方法)
- `apps/server/src/modules/app/activity/activity.service.ts` (handleOrderCompleted 方法)

**关键代码**：
```typescript
// 给商家账户增加余额
await this.accountService.addMerchantBalance(
  merchantId,
  settlementAmount, // 订单金额 - 服务费
  transactionNo,
  'settlement',
  settlement.id,
  settlementNo,
  `商家周结算：${periodStart} ~ ${periodEnd}`
);

// 给平台账户增加服务费收入
await this.accountService.addPlatformBalance(
  serviceFee,
  transactionNo,
  'settlement',
  settlement.id,
  settlementNo,
  `商家 ${merchantId} 周结算服务费：${periodStart} ~ ${periodEnd}`
);

// 邀请返现（如果有）
await this.accountService.addUserBalance(
  invitation.inviterId,
  amount,
  transactionNo,
  'invite_cashback',
  cashback.id,
  order.orderNo,
  `邀请返现 - 订单${order.orderNo}第${orderIndex}单`,
);

await this.accountService.deductPlatformCashback(
  amount,
  transactionNo,
  'invite_cashback',
  cashback.id,
  order.orderNo,
  `邀请返现支出 - 用户${invitation.inviterId}订单${order.orderNo}`,
);
```

### 3. 订单退款流程

```
用户申请退款
  ↓
调用第三方支付退款API
  ↓
系统总账户 +退款金额
  ↓
订单状态：pending_confirm/pending_checkin → refunded
```

**涉及文件**：
- `apps/server/src/modules/shared/finance/refund.service.ts` (processRefund 方法)

**关键代码**：
```typescript
// 记录系统总账户退款
await this.accountService.addSystemRefund(
  order.payAmount,
  transactionNo,
  'order_refund',
  order.id,
  order.orderNo,
  `订单退款 - ${order.orderNo}`,
);
```

### 4. 提现流程

#### 用户提现

```
用户申请提现
  ↓
用户账户：balance → frozen_balance
  ↓
管理员审核通过
  ↓
管理员确认打款
  ↓
用户账户 -提现金额（从frozen_balance扣减）
系统总账户 +提现金额
  ↓
提现状态：pending → approved → paid
```

#### 商家提现

```
商家申请提现
  ↓
商家账户：balance → frozen_balance
  ↓
管理员审核通过
  ↓
管理员确认打款
  ↓
商家账户 -提现金额（从frozen_balance扣减）
系统总账户 +提现金额
  ↓
提现状态：pending → approved → paid
```

**涉及文件**：
- `apps/server/src/modules/shared/finance/withdrawal.service.ts` (payUserWithdrawal, payMerchantWithdrawal 方法)

**关键代码**：
```typescript
// 扣减用户账户余额
await this.accountService.deductUserBalance(
  withdrawal.userId,
  Number(withdrawal.actualAmount),
  transactionNo,
  'withdraw',
  withdrawal.id,
  withdrawal.withdrawNo,
  `用户提现 - ${withdrawal.paymentChannel}`
);

// 记录系统总账户提现
await this.accountService.addSystemWithdrawal(
  Number(withdrawal.actualAmount),
  transactionNo,
  'user_withdraw',
  withdrawal.id,
  withdrawal.withdrawNo,
  `用户 ${withdrawal.userId} 提现 - ${withdrawal.paymentChannel}`,
);
```

## 结算周期

### 周结算机制

**执行时间**：每周一凌晨 2:00  
**结算周期**：上周一 00:00:00 ~ 上周日 23:59:59  
**结算对象**：状态为 `completed` 的订单  
**判断依据**：订单的 `checkout_at`（离店时间）字段

### 定时任务配置

**文件位置**：`apps/server/src/schedule/settlement.schedule.ts`

```typescript
@Cron('0 2 * * 1') // 每周一凌晨2点
async handleWeeklySettlement() {
  await this.settlementService.handleWeeklySettlement();
}
```

### 结算逻辑

1. **查询上周已完成订单**
   ```typescript
   const orders = await this.orderRepo
     .createQueryBuilder('o')
     .where('o.status = :status', { status: 'completed' })
     .andWhere('o.checkout_at BETWEEN :start AND :end', {
       start: `${lastWeekStart} 00:00:00`,
       end: `${lastWeekEnd} 23:59:59`
     })
     .getMany();
   ```

2. **按商家分组统计**
   - 订单数量：`orderCount`
   - 订单总额：`orderAmount`
   - 服务费总额：`serviceFee`
   - 结算金额：`settlementAmount = orderAmount - serviceFee`

3. **生成结算单**
   - 创建 `Settlement` 记录
   - 创建 `SettlementItem` 记录

4. **执行资金转账**
   - 商家账户增加
   - 平台账户增加（服务费）
   - 复式记账

### 防止重复结算

```typescript
// 检查该周期是否已经结算过
const existingSettlements = await this.settlementRepo.count({
  where: {
    periodStart: lastWeekStart,
    periodEnd: lastWeekEnd
  }
});

if (existingSettlements > 0) {
  throw new Error(`该周期 ${lastWeekStart} ~ ${lastWeekEnd} 已经结算过，无法重复结算`);
}
```

---

## 服务费计算

### 计算公式

```typescript
// 用户实付金额
payAmount = totalAmount - couponDiscount

// 服务费
serviceFee = Math.round(payAmount * serviceFeeRate * 100) / 100

// 商家实收金额
merchantIncome = payAmount - serviceFee
```

### 服务费率配置

**默认值**：5% (0.05)  
**配置位置**：`platform_configs` 表  
**配置键**：`service_fee_rate`

### 示例计算

```
房费总额：1000元
优惠券抵扣：100元
服务费率：5%

用户实付：1000 - 100 = 900元
服务费：900 × 0.05 = 45元
商家实收：900 - 45 = 855元
平台收入：45元
```

---

## 核心服务

### AccountService

账户操作核心服务，提供所有账户的增减操作。

**位置**：`apps/server/src/modules/shared/finance/account.service.ts`

**主要方法**：

#### 系统总账户操作
- `getSystemAccount()` - 获取系统总账户
- `addSystemIncome(amount, ...)` - 记录用户实付收入
- `addSystemRefund(amount, ...)` - 记录退款
- `addSystemWithdrawal(amount, ...)` - 记录提现

#### 平台账户操作
- `addPlatformBalance(serviceFee, ...)` - 记录服务费收入
- `deductPlatformCashback(amount, ...)` - 记录邀请返现支出

**核心代码示例**：

```typescript
// 平台账户增加余额（服务费收入）
async addPlatformBalance(
  amount: number,
  transactionNo: string,
  businessType: string,
  businessId: number,
  businessNo: string,
  remark: string,
): Promise<void> {
  const queryRunner = this.dataSource.createQueryRunner();
  await queryRunner.connect();
  await queryRunner.startTransaction();

  try {
    // 使用悲观锁查询账户
    const account = await queryRunner.manager.findOne(PlatformAccount, {
      where: { account_name: '主账户' },
      lock: { mode: 'pessimistic_write' },
    });

    // 金额精度控制
    const amountNum = Number(amount);
    const balanceBefore = Number(account.balance);
    const balanceAfter = parseFloat((balanceBefore + amountNum).toFixed(2));

    // 更新账户
    account.balance = balanceAfter;
    account.total_income = parseFloat((Number(account.total_income) + amountNum).toFixed(2));
    account.version += 1;

    await queryRunner.manager.save(account);

    // 记录交易流水
    const transaction = queryRunner.manager.create(PlatformTransaction, {
      transactionNo,
      accountId: account.id,
      direction: 'income',
      amount: amountNum,
      balanceBefore,
      balanceAfter,
      transactionType: 'service_fee',
      businessType,
      businessId,
      businessNo,
      remark,
    });

    await queryRunner.manager.save(transaction);
    await queryRunner.commitTransaction();
  } catch (error) {
    await queryRunner.rollbackTransaction();
    throw error;
  } finally {
    await queryRunner.release();
  }
}
```

#### 商家账户操作
- `addMerchantBalance(merchantId, amount, ...)` - 增加商家余额
- `deductMerchantBalance(merchantId, amount, ...)` - 扣减商家余额
- `freezeMerchantBalance(merchantId, amount)` - 冻结商家余额
- `unfreezeMerchantBalance(merchantId, amount)` - 解冻商家余额

#### 用户账户操作
- `addUserBalance(userId, amount, ...)` - 增加用户余额
- `deductUserBalance(userId, amount, ...)` - 扣减用户余额
- `freezeUserBalance(userId, amount)` - 冻结用户余额
- `unfreezeUserBalance(userId, amount)` - 解冻用户余额

**安全机制**：
- 使用数据库事务确保操作原子性
- 使用悲观锁（`pessimistic_write`）防止并发修改
- 使用乐观锁（`version` 字段）检测并发冲突
- 所有金额计算使用 `Number()` 和 `toFixed(2)` 确保精度

### SettlementService

订单结算服务，负责商家的周结算。

**位置**：`apps/server/src/modules/shared/finance/settlement.service.ts`

**主要功能**：
- 每周一凌晨2点自动执行周结算
- 统计上周已完成订单
- 按商家分组计算结算金额
- 更新商家账户和平台账户

### RefundService

退款服务，负责订单退款处理。

**位置**：`apps/server/src/modules/shared/finance/refund.service.ts`

**主要功能**：
- 调用第三方支付退款API（微信支付、支付宝）
- 更新订单状态
- 记录系统总账户退款

### WithdrawalService

提现服务，负责用户和商家的提现申请、审核、打款。

**位置**：`apps/server/src/modules/shared/finance/withdrawal.service.ts`

**主要功能**：
- 提现申请（冻结余额）
- 提现审核（通过/拒绝）
- 提现打款（扣减余额，记录系统总账户提现）

### ReportService

财务报表服务，提供财务数据统计。

**位置**：`apps/server/src/modules/shared/finance/report.service.ts`

**主要功能**：
- 财务总览（系统总账户、平台账户、商家账户、用户账户统计）
- 财务趋势（按日统计收入支出）
- 资金守恒验证

## 数据库表结构

### system_accounts（系统总账户表）

```sql
CREATE TABLE `system_accounts` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `account_name` VARCHAR(50) NOT NULL COMMENT '账户名称',
  `balance` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '可用余额',
  `total_income` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '累计收入（用户实付总额）',
  `total_refund` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '累计退款',
  `total_withdrawn` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '累计提现',
  `version` INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_account_name` (`account_name`)
) COMMENT='系统总账户表';
```

### system_transactions（系统总账户交易流水表）

```sql
CREATE TABLE `system_transactions` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `transaction_no` VARCHAR(64) NOT NULL COMMENT '交易流水号',
  `account_id` BIGINT UNSIGNED NOT NULL COMMENT '账户ID',
  `direction` ENUM('income','expense') NOT NULL COMMENT '交易方向',
  `amount` DECIMAL(12,2) NOT NULL COMMENT '交易金额',
  `balance_before` DECIMAL(12,2) NOT NULL COMMENT '交易前余额',
  `balance_after` DECIMAL(12,2) NOT NULL COMMENT '交易后余额',
  `transaction_type` VARCHAR(50) NOT NULL COMMENT '交易类型',
  `business_type` VARCHAR(50) NOT NULL COMMENT '业务类型',
  `business_id` BIGINT UNSIGNED NOT NULL COMMENT '业务ID',
  `business_no` VARCHAR(64) NOT NULL COMMENT '业务单号',
  `remark` VARCHAR(500) DEFAULT NULL COMMENT '备注',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_transaction_no` (`transaction_no`),
  KEY `idx_account_id` (`account_id`),
  KEY `idx_business` (`business_type`, `business_id`),
  KEY `idx_created_at` (`created_at`)
) COMMENT='系统总账户交易流水表';
```

### platform_accounts（平台账户表）

```sql
CREATE TABLE `platform_accounts` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `account_name` VARCHAR(50) NOT NULL COMMENT '账户名称',
  `balance` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '可用余额',
  `total_income` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '累计收入（服务费收入）',
  `total_expense` DECIMAL(12,2) NOT NULL DEFAULT 0.00 COMMENT '累计支出（邀请返现支出）',
  `version` INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_account_name` (`account_name`)
) COMMENT='平台账户表';
```

## 前端展示

### 1. 财务总览页面

**位置**：`apps/platform-admin/src/pages/finance/Dashboard.tsx`

**展示内容**：

1. **系统总账户金额**（突出显示）
   - 计算公式：用户实付 - 退款 - 提现
   - 资金守恒验证：= 商家账户余额 + 用户账户余额 + 平台净收益

2. **平台净收益**
   - 服务费收入 - 邀请返现支出

3. **用户总余额**
   - 所有用户账户余额总和
   - 用户账户数量

4. **商家总余额**
   - 所有商家账户余额总和
   - 商家账户数量

5. **今日统计**
   - 今日订单数
   - 今日收入
   - 今日支出
   - 今日净收益

### 2. 平台钱包页面

**位置**：`apps/platform-admin/src/pages/finance/PlatformWallet.tsx`

**功能特性**：
- 钱包余额、可提现金额、冻结金额、服务费收入展示
- 账户总收入、总支出、其他收入统计
- 钱包详情查看
- 申请提现功能（集成在页面内）

### 3. 平台交易记录

**位置**：`apps/platform-admin/src/pages/finance/PlatformTransactions.tsx`

**功能特性**：
- 交易流水查询（按流水号、方向、类型、时间筛选）
- 交易详情展示
- 分页展示

### 4. 结算管理

**位置**：`apps/platform-admin/src/pages/finance/Settlements.tsx`

**功能特性**：
- 结算单列表查询
- 结算单详情查看
- 预览周结算数据
- 手动执行周结算

### 5. 商家提现审核

**位置**：`apps/platform-admin/src/pages/finance/Withdrawals.tsx`

**功能特性**：
- 商家提现申请列表
- 审核通过/拒绝
- 确认打款

---

## API接口

### 平台钱包接口

#### 1. 查询平台账户

**接口**：`GET /api/admin/finance/platform-accounts`  
**权限**：平台管理员

**响应示例**：
```json
{
  "id": 1,
  "account_name": "主账户",
  "balance": 40.00,
  "frozen_balance": 0.00,
  "total_income": 1000.00,
  "total_expense": 960.00,
  "status": "active"
}
```

#### 2. 平台申请提现

**接口**：`POST /api/admin/finance/platform-withdrawals`  
**权限**：平台管理员

**请求参数**：
```json
{
  "amount": 30.00,
  "bankName": "中国工商银行",
  "bankAccount": "6222021234567890123",
  "accountName": "某某科技有限公司",
  "remark": "提现备注"
}
```

### 结算管理接口

#### 3. 预览周结算

**接口**：`GET /api/admin/finance/settlements/preview-weekly`  
**权限**：平台管理员

**响应示例**：
```json
{
  "periodStart": "2026-05-13",
  "periodEnd": "2026-05-19",
  "totalOrders": 45,
  "totalAmount": 35000.00,
  "totalServiceFee": 1750.00,
  "totalSettlementAmount": 33250.00,
  "merchants": [...]
}
```

#### 4. 执行周结算

**接口**：`POST /api/admin/finance/settlements/execute-weekly`  
**权限**：平台管理员

---

## 扩展方案

### 未来增加其他收入

#### 1. 数据库增加字段

```sql
ALTER TABLE platform_accounts 
ADD COLUMN total_ad_revenue DECIMAL(12,2) DEFAULT 0 COMMENT '累计广告收入',
ADD COLUMN total_membership_fee DECIMAL(12,2) DEFAULT 0 COMMENT '累计会员费收入',
ADD COLUMN total_other_income DECIMAL(12,2) DEFAULT 0 COMMENT '累计其他收入';
```

#### 2. 后端增加方法

```typescript
// 广告收入
async addPlatformAdRevenue(amount: number, ...): Promise<void> {
  account.balance += amount;
  account.total_income += amount;
  account.total_ad_revenue += amount;
}

// 会员费收入
async addPlatformMembershipFee(amount: number, ...): Promise<void> {
  account.balance += amount;
  account.total_income += amount;
  account.total_membership_fee += amount;
}
```

#### 3. 前端增加展示

```typescript
<Statistic
  title="广告收入"
  value={account.total_ad_revenue}
  precision={2}
  suffix="元"
/>

<Statistic
  title="会员费收入"
  value={account.total_membership_fee}
  precision={2}
  suffix="元"
/>
```

#### 4. 调整可提现计算

```typescript
// 方案1：继续使用各项收入累加
const withdrawableAmount = (
  total_service_fee + 
  total_ad_revenue + 
  total_membership_fee
) - frozen_balance;

// 方案2：直接使用钱包余额（推荐）
const withdrawableAmount = balance - frozen_balance;
```

**推荐方案2**，因为：
- `balance` 已经包含了所有收入和支出
- 不需要每次增加新收入类型都修改代码
- 更简洁、更易维护

---

## 前端展示

## 安全保障

### 1. 数据库事务

所有涉及账户操作的方法都使用数据库事务，确保操作的原子性：

```typescript
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();

try {
  // 账户操作
  await queryRunner.commitTransaction();
} catch (error) {
  await queryRunner.rollbackTransaction();
  throw error;
} finally {
  await queryRunner.release();
}
```

### 2. 悲观锁

在查询账户时使用悲观锁，防止并发修改：

```typescript
const account = await queryRunner.manager.findOne(SystemAccount, {
  where: { account_name: '系统总账户' },
  lock: { mode: 'pessimistic_write' },
});
```

### 3. 乐观锁

使用 `version` 字段实现乐观锁，检测并发冲突：

```typescript
account.version += 1;
await queryRunner.manager.save(account);
```

### 4. 金额精度控制

所有金额计算都使用 `Number()` 转换和 `toFixed(2)` 保留两位小数：

```typescript
const amountNum = Number(amount);
const balanceBefore = Number(account.balance);
const balanceAfter = parseFloat((balanceBefore + amountNum).toFixed(2));
```

### 5. 余额校验

在扣减余额前检查余额是否足够：

```typescript
if (balanceBefore < amount) {
  throw new BadRequestException('账户余额不足');
}
```

### 6. 交易流水

所有账户操作都记录详细的交易流水，包括：
- 交易流水号（唯一）
- 交易前后余额
- 交易类型和业务类型
- 关联的业务ID和业务单号
- 备注信息

## 测试验证

### 资金守恒验证

定期执行以下查询验证资金守恒：

```sql
-- 查询系统总账户余额
SELECT balance FROM system_accounts WHERE account_name = '系统总账户';

-- 查询商家账户余额总和
SELECT SUM(balance) FROM merchant_accounts;

-- 查询用户账户余额总和
SELECT SUM(balance) FROM user_accounts;

-- 查询平台账户余额
SELECT balance FROM platform_accounts WHERE account_name = '主账户';

-- 验证：系统总账户余额 = 商家账户余额 + 用户账户余额 + 平台账户余额
```

### 完整流程测试

1. **订单支付测试**
   - 创建订单并支付
   - 验证系统总账户余额增加

2. **订单结算测试**
   - 订单完成后触发结算
   - 验证商家账户余额增加
   - 验证平台账户余额增加（服务费）
   - 如果有邀请关系，验证用户账户余额增加（返现）

3. **订单退款测试**
   - 申请退款
   - 验证系统总账户退款金额增加

4. **提现测试**
   - 申请提现
   - 审核通过
   - 确认打款
   - 验证账户余额扣减
   - 验证系统总账户提现金额增加

5. **资金守恒测试**
   - 执行多个订单流程
   - 验证资金守恒公式始终成立

## 部署说明

### 数据库初始化

1. 执行数据库迁移脚本：
```bash
# 重新初始化数据库（会清空所有数据）
mysql -u root -p < database/migrations/001_init_schema.sql
```

2. 初始化系统总账户：
```sql
INSERT INTO system_accounts (account_name, balance, total_income, total_refund, total_withdrawn, status)
VALUES ('SYSTEM_MAIN', 0.00, 0.00, 0.00, 0.00, 'active');
```

3. 初始化平台账户：
```sql
INSERT INTO platform_accounts (account_name, balance, frozen_balance, total_income, total_expense, status)
VALUES ('PLATFORM_MAIN', 0.00, 0.00, 0.00, 0.00, 'active');
```

或者直接执行种子数据脚本：
```bash
mysql -u root -p rent_platform < database/seeds/001_init_data.sql
```

### 服务启动

```bash
# 安装依赖
pnpm install

# 启动后端服务
cd apps/server
pnpm run start:dev

# 启动平台管理后台
cd apps/platform-admin
pnpm run dev
```

## 常见问题

### Q1: 为什么要分系统总账户和平台账户？

A: 系统总账户记录的是平台内所有未提现的资金总额，用于验证资金守恒。平台账户记录的是平台的净收益（服务费 - 邀请返现），用于计算平台的实际盈利。两者职责不同，分开管理更清晰。

### Q2: 订单支付时为什么只更新系统总账户，不更新商家账户？

A: 订单支付时资金进入平台，但还未分配给商家。只有订单完成（用户离店）后才进行结算，将资金分配给商家。这样可以防止用户退款时出现商家已收款的情况。

### Q3: 邀请返现为什么要从平台账户扣减？

A: 邀请返现是平台的营销成本，应该从平台的收益中扣除。平台的净收益 = 服务费收入 - 邀请返现支出。

### Q4: 如何确保资金安全？

A: 系统采用多重安全机制：
- 数据库事务确保操作原子性
- 悲观锁和乐观锁防止并发问题
- 详细的交易流水记录
- 资金守恒验证
- 余额校验

### Q5: 如果发现账户余额不对怎么办？

A: 
1. 查看交易流水，定位问题操作
2. 检查是否有并发操作导致的问题
3. 验证资金守恒公式是否成立
4. 如果是数据错误，需要手动调整并记录原因

## 更新日志

### 2024-01-XX - 账户体系重构

**重大变更**：
- 新增系统总账户，记录平台内所有未提现的资金
- 修改平台账户职责，只记录平台净收益
- 修改订单支付逻辑，更新系统总账户
- 修改订单结算逻辑，同时更新商家账户和平台账户
- 修改邀请返现逻辑，从平台账户扣减
- 修改退款逻辑，更新系统总账户
- 修改提现逻辑，更新系统总账户
- 修改财务报表，使用新的账户数据
- 修改前端页面，展示新的账户结构

**影响范围**：
- 数据库表结构变更，需要重新初始化数据库
- 所有涉及账户操作的代码都需要更新
- 前端页面需要更新

**升级步骤**：
1. 备份现有数据库
2. 执行新的数据库迁移脚本
3. 更新后端代码
4. 更新前端代码
5. 重启服务
6. 验证资金守恒

## 联系方式

如有问题，请联系开发团队。

---

## 相关文档

- [财务数据库设计](../database/finance-database.md)
- [邀请码系统设计](./invite-system.md)
- [项目文档索引](../README.md)

---

**版本**：v3.0（合并版）  
**最后更新**：2024-01-XX  
**维护团队**：开发团队
