811 lines
34 KiB
Markdown
811 lines
34 KiB
Markdown
# 财务与收费域 - 详细设计
|
||
|
||
**文档类型**: 详细设计文档
|
||
**生成日期**: 2026-05-18
|
||
**数据来源**: REVERSE-FINANCE.md(反推文档)+ 04-FINANCE.md(原设计文档)+ 实际代码分析
|
||
|
||
---
|
||
|
||
## 一、功能点清单
|
||
|
||
| 编号 | 功能模块 | 功能点 | 实现状态 | 说明 |
|
||
|------|---------|--------|---------|------|
|
||
| FIN-001 | 能耗计量管理 | 计量点CRUD | 已实现 | module-mdm 中 EnergyMeter |
|
||
| FIN-002 | 能耗计量管理 | 计量点编码自动生成 | 已实现 | EM + yyyyMMddHHmmss |
|
||
| FIN-003 | 能耗计量管理 | 计量点软删除 | 已实现 | 状态设为 INACTIVE |
|
||
| FIN-004 | 能耗录入 | 能耗数据录入 | 已实现 | 手动录入 + IoT预留 |
|
||
| FIN-005 | 能耗录入 | 读数递增校验 | 已实现 | 当前读数 >= 上次读数 |
|
||
| FIN-006 | 能耗录入 | 自动计算消耗量与费用 | 已实现 | consumption = current - previous; amount = consumption * unitPrice |
|
||
| FIN-007 | 能耗统计 | 按类型统计消耗 | 已实现(有缺陷) | 当前全部归入LIGHTING,需修复 |
|
||
| FIN-008 | 能耗统计 | 单方能耗 | 已实现 | 遍历项目ACTIVE计量点累加 |
|
||
| FIN-009 | 收费项目管理 | 收费项目CRUD | 未实现 | FeeItem 实体不存在 |
|
||
| FIN-010 | 收费项目管理 | 周期性收费配置 | 未实现 | 按月/季/年收费 |
|
||
| FIN-011 | 收费项目管理 | 一次性收费配置 | 未实现 | 临时收费项目 |
|
||
| FIN-012 | 收费项目管理 | 按面积计费配置 | 未实现 | 面积 * 单价 |
|
||
| FIN-013 | 收费项目管理 | 按用量计费配置 | 未实现 | 用量 * 单价(对接能耗) |
|
||
| FIN-014 | 收费项目管理 | 固定金额计费配置 | 未实现 | 每月固定金额 |
|
||
| FIN-015 | 账单管理 | 账单自动生成 | 未实现 | 根据收费项目规则按账期生成 |
|
||
| FIN-016 | 账单管理 | 账单手动生成 | 未实现 | 人工创建单笔账单 |
|
||
| FIN-017 | 账单管理 | 批量账单生成 | 未实现 | 一次性为项目所有业主生成 |
|
||
| FIN-018 | 账单管理 | 账单状态流转 | 未实现 | UNPAID/PARTIAL_PAID/PAID/OVERDUE/CANCELLED |
|
||
| FIN-019 | 账单管理 | 催缴提醒 | 未实现 | 到期前3天提醒 + 逾期催缴 |
|
||
| FIN-020 | 账单管理 | 账单导出 | 未实现 | Excel/PDF 格式 |
|
||
| FIN-021 | 支付管理 | 线下收款登记 | 未实现 | 现金/银行转账/刷卡 |
|
||
| FIN-022 | 支付管理 | 线上支付对接 | 未实现 | 微信/支付宝 |
|
||
| FIN-023 | 支付管理 | 支付确认 | 未实现 | 支付状态确认 |
|
||
| FIN-024 | 支付管理 | 支付记录查询 | 未实现 | 按账单/业主/时间查询 |
|
||
| FIN-025 | 退款管理 | 退款申请 | 未实现 | 业主发起退款 |
|
||
| FIN-026 | 退款管理 | 退款审核 | 未实现 | 审批流程 |
|
||
| FIN-027 | 退款管理 | 退款执行 | 未实现 | 原路退回/线下退款 |
|
||
| FIN-028 | 滞纳金 | 滞纳金自动计算 | 未实现 | 逾期天数 * 日利率 |
|
||
| FIN-029 | 滞纳金 | 滞纳金上限控制 | 未实现 | 不超过 maxLateFee |
|
||
| FIN-030 | 能耗对接 | 能耗数据与账单对接 | 未实现 | EnergyConsumption -> FeeBill |
|
||
| FIN-031 | 能耗修复 | 修复按类型统计 | 未实现 | 按 meter.energyType 真正分项汇总 |
|
||
| FIN-032 | 能耗修复 | 统一前后端能源类型枚举 | 未实现 | 后端6种 vs 前端5种 |
|
||
| FIN-033 | 财务报表 | 收费统计 | 未实现 | 按项目/类型/时间维度 |
|
||
| FIN-034 | 财务报表 | 欠费分析 | 未实现 | 逾期/欠费金额统计 |
|
||
| FIN-035 | 财务报表 | 收入趋势 | 未实现 | 月度/季度趋势图 |
|
||
|
||
---
|
||
|
||
## 二、数据结构设计
|
||
|
||
### 2.1 已实现实体
|
||
|
||
#### 2.1.1 EnergyMeter(能源计量点)
|
||
|
||
**所在模块**: module-mdm
|
||
**数据库表**: `ops_energy_meter`
|
||
**源码**: `ether-pms/module-mdm/src/main/java/com/ether/pms/mdm/entity/EnergyMeter.java`
|
||
|
||
| 字段名 | 类型 | 数据库列名 | 约束 | 说明 |
|
||
|--------|------|-----------|------|------|
|
||
| id | UUID | id | PK | 主键 |
|
||
| projectId | UUID | project_id | NOT NULL | 所属项目 |
|
||
| meterCode | String | meter_code | NOT NULL, UNIQUE | 计量点编码(EM + yyyyMMddHHmmss) |
|
||
| meterName | String | meter_name | NOT NULL | 计量点名称 |
|
||
| energyType | EnergyType | energy_type | NOT NULL | 能源类型枚举 |
|
||
| spaceNodeId | UUID | space_node_id | -- | 关联空间节点 |
|
||
| installationLocation | String | installation_location | -- | 安装位置 |
|
||
| ratedCapacity | BigDecimal(10,2) | rated_capacity | -- | 额定容量 |
|
||
| unitPrice | BigDecimal(10,4) | unit_price | -- | 单价(4位小数精度) |
|
||
| status | Status | status | NOT NULL, 默认ACTIVE | 状态枚举 |
|
||
| createdAt | LocalDateTime | created_at | -- | 创建时间 |
|
||
| updatedAt | LocalDateTime | updated_at | -- | 更新时间 |
|
||
|
||
**枚举定义**:
|
||
|
||
```java
|
||
public enum EnergyType {
|
||
LIGHTING("照明插座用电"),
|
||
HVAC("空调用电"),
|
||
POWER("动力用电"),
|
||
SPECIAL("特殊用电"),
|
||
WATER("给排水"),
|
||
GAS("燃气");
|
||
}
|
||
|
||
public enum Status {
|
||
ACTIVE, INACTIVE
|
||
}
|
||
```
|
||
|
||
#### 2.1.2 EnergyConsumption(能耗记录)
|
||
|
||
**所在模块**: module-mdm
|
||
**数据库表**: `ops_energy_consumption`
|
||
**源码**: `ether-pms/module-mdm/src/main/java/com/ether/pms/mdm/entity/EnergyConsumption.java`
|
||
|
||
| 字段名 | 类型 | 数据库列名 | 约束 | 说明 |
|
||
|--------|------|-----------|------|------|
|
||
| id | UUID | id | PK | 主键 |
|
||
| projectId | UUID | project_id | NOT NULL | 所属项目 |
|
||
| meterId | UUID | meter_id | NOT NULL | 关联计量点 |
|
||
| consumptionDate | LocalDate | consumption_date | NOT NULL | 记录日期 |
|
||
| previousReading | BigDecimal(12,2) | previous_reading | -- | 上次读数 |
|
||
| currentReading | BigDecimal(12,2) | current_reading | -- | 当前读数 |
|
||
| consumption | BigDecimal(12,2) | consumption | NOT NULL | 消耗量 = current - previous |
|
||
| amount | BigDecimal(10,2) | amount | -- | 费用 = consumption * unitPrice |
|
||
| recordedBy | UUID | recorded_by | -- | 记录人 |
|
||
| recordMethod | RecordMethod | record_method | -- | 记录方式,默认MANUAL |
|
||
| remarks | String(1000) | remarks | -- | 备注 |
|
||
| createdAt | LocalDateTime | created_at | -- | 创建时间 |
|
||
|
||
**数据库索引**:
|
||
|
||
```sql
|
||
idx_ec_meter_date -- (meter_id, consumption_date)
|
||
idx_ec_project_date -- (project_id, consumption_date)
|
||
```
|
||
|
||
**枚举定义**:
|
||
|
||
```java
|
||
public enum RecordMethod {
|
||
MANUAL, // 手动录入
|
||
IOT // IoT自动采集
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2.2 待实现实体
|
||
|
||
#### 2.2.1 FeeItem(收费项目)
|
||
|
||
**目标模块**: module-finance(待创建)
|
||
**目标表**: `fin_fee_item`
|
||
|
||
| 字段名 | 类型 | 数据库列名 | 约束 | 说明 |
|
||
|--------|------|-----------|------|------|
|
||
| id | UUID | id | PK | 主键 |
|
||
| projectId | UUID | project_id | NOT NULL | 所属项目 |
|
||
| code | VARCHAR(50) | code | NOT NULL, UNIQUE | 收费项目编码(FI + yyyyMMddHHmmss) |
|
||
| name | VARCHAR(100) | name | NOT NULL | 收费项目名称 |
|
||
| type | VARCHAR(20) | type | NOT NULL | 收费类型枚举 |
|
||
| billingMethod | VARCHAR(20) | billing_method | NOT NULL | 计费方式枚举 |
|
||
| unitPrice | DECIMAL(12,4) | unit_price | -- | 单价(按用量/面积计费时使用) |
|
||
| unit | VARCHAR(20) | unit | -- | 计量单位(kWh/吨/平方米/月/次) |
|
||
| fixedAmount | DECIMAL(12,2) | fixed_amount | -- | 固定金额(FIXED计费方式) |
|
||
| billDay | INT | bill_day | -- | 出账日(每月几号出账,1-28) |
|
||
| dueDay | INT | due_day | -- | 到期日(出账后第N天到期) |
|
||
| overdueDay | INT | overdue_day | -- | 逾期日(到期后第N天开始计滞纳金) |
|
||
| enableLateFee | BOOLEAN | enable_late_fee | NOT NULL, 默认false | 是否启用滞纳金 |
|
||
| lateFeeRate | DECIMAL(8,6) | late_fee_rate | -- | 日滞纳金利率(如0.0005 = 万分之五/天) |
|
||
| maxLateFee | DECIMAL(12,2) | max_late_fee | -- | 滞纳金上限金额 |
|
||
| description | VARCHAR(500) | description | -- | 收费项目说明 |
|
||
| status | VARCHAR(20) | status | NOT NULL, 默认ENABLED | 状态:ENABLED/DISABLED |
|
||
| createdAt | TIMESTAMP | created_at | NOT NULL | 创建时间 |
|
||
| updatedAt | TIMESTAMP | updated_at | NOT NULL | 更新时间 |
|
||
| createdBy | UUID | created_by | -- | 创建人 |
|
||
|
||
**枚举定义**:
|
||
|
||
```java
|
||
public enum FeeType {
|
||
PROPERTY("物业费"),
|
||
PARKING("停车费"),
|
||
WATER("水费"),
|
||
ELECTRICITY("电费"),
|
||
GAS("燃气费"),
|
||
HEATING("供暖费"),
|
||
REPAIR_FUND("维修基金"),
|
||
OTHER("其他");
|
||
}
|
||
|
||
public enum BillingMethod {
|
||
FIXED("固定金额"), // 每月固定金额
|
||
AREA("按面积计费"), // 面积 * 单价
|
||
USAGE("按用量计费"), // 用量 * 单价(对接能耗)
|
||
CUSTOM("自定义"); // 自定义计费规则
|
||
}
|
||
```
|
||
|
||
**数据库索引**:
|
||
|
||
```sql
|
||
idx_fi_project_status -- (project_id, status)
|
||
idx_fi_code -- (code) -- UNIQUE约束自带索引
|
||
idx_fi_type -- (type, status)
|
||
```
|
||
|
||
**外键关系**:
|
||
|
||
```sql
|
||
fk_fi_project -- project_id REFERENCES mdm_project(id)
|
||
```
|
||
|
||
---
|
||
|
||
#### 2.2.2 FeeBill(收费账单)
|
||
|
||
**目标模块**: module-finance(待创建)
|
||
**目标表**: `fin_fee_bill`
|
||
|
||
| 字段名 | 类型 | 数据库列名 | 约束 | 说明 |
|
||
|--------|------|-----------|------|------|
|
||
| id | UUID | id | PK | 主键 |
|
||
| billNo | VARCHAR(30) | bill_no | NOT NULL, UNIQUE | 账单编号(BL + yyyyMMdd + 4位序号) |
|
||
| feeItemId | UUID | fee_item_id | NOT NULL | 关联收费项目 |
|
||
| projectId | UUID | project_id | NOT NULL | 所属项目 |
|
||
| spaceNodeId | UUID | space_node_id | -- | 关联空间节点(房产) |
|
||
| ownerId | UUID | owner_id | -- | 关联业主ID |
|
||
| billPeriod | VARCHAR(20) | bill_period | NOT NULL | 账期(如2026-05) |
|
||
| billDate | DATE | bill_date | NOT NULL | 出账日期 |
|
||
| dueDate | DATE | due_date | NOT NULL | 到期日期 |
|
||
| overdueDate | DATE | overdue_date | -- | 逾期日期 |
|
||
| usageAmount | DECIMAL(12,2) | usage_amount | -- | 用量(按用量计费时) |
|
||
| usageUnit | VARCHAR(20) | usage_unit | -- | 用量单位 |
|
||
| area | DECIMAL(12,2) | area | -- | 面积(按面积计费时) |
|
||
| amount | DECIMAL(12,2) | amount | NOT NULL | 应收金额 |
|
||
| lateFee | DECIMAL(12,2) | late_fee | 默认0 | 滞纳金 |
|
||
| discount | DECIMAL(12,2) | discount | 默认0 | 优惠金额 |
|
||
| payableAmount | DECIMAL(12,2) | payable_amount | NOT NULL | 应付金额 = amount + lateFee - discount |
|
||
| paidAmount | DECIMAL(12,2) | paid_amount | 默认0 | 已付金额 |
|
||
| status | VARCHAR(20) | status | NOT NULL, 默认UNPAID | 账单状态枚举 |
|
||
| sourceType | VARCHAR(20) | source_type | -- | 来源类型:AUTO/MANUAL/IMPORT |
|
||
| sourceId | UUID | source_id | -- | 来源ID(如能耗记录ID) |
|
||
| remark | VARCHAR(500) | remark | -- | 备注 |
|
||
| createdAt | TIMESTAMP | created_at | NOT NULL | 创建时间 |
|
||
| updatedAt | TIMESTAMP | updated_at | NOT NULL | 更新时间 |
|
||
| createdBy | UUID | created_by | -- | 创建人 |
|
||
|
||
**枚举定义**:
|
||
|
||
```java
|
||
public enum BillStatus {
|
||
UNPAID("未支付"),
|
||
PARTIAL_PAID("部分支付"),
|
||
PAID("已支付"),
|
||
OVERDUE("已逾期"),
|
||
CANCELLED("已取消");
|
||
}
|
||
|
||
public enum BillSourceType {
|
||
AUTO("自动生成"),
|
||
MANUAL("手动创建"),
|
||
IMPORT("导入");
|
||
}
|
||
```
|
||
|
||
**数据库索引**:
|
||
|
||
```sql
|
||
idx_fb_bill_no -- (bill_no) -- UNIQUE约束自带索引
|
||
idx_fb_project_period -- (project_id, bill_period)
|
||
idx_fb_owner_status -- (owner_id, status)
|
||
idx_fb_fee_item -- (fee_item_id, bill_period)
|
||
idx_fb_space_node -- (space_node_id, bill_period)
|
||
idx_fb_due_date -- (due_date, status) -- 用于催缴查询
|
||
idx_fb_overdue -- (status, overdue_date) -- 用于滞纳金计算
|
||
```
|
||
|
||
**外键关系**:
|
||
|
||
```sql
|
||
fk_fb_fee_item -- fee_item_id REFERENCES fin_fee_item(id)
|
||
fk_fb_project -- project_id REFERENCES mdm_project(id)
|
||
fk_fb_space_node -- space_node_id REFERENCES mdm_space_node(id)
|
||
```
|
||
|
||
---
|
||
|
||
#### 2.2.3 FeePayment(支付记录)
|
||
|
||
**目标模块**: module-finance(待创建)
|
||
**目标表**: `fin_fee_payment`
|
||
|
||
| 字段名 | 类型 | 数据库列名 | 约束 | 说明 |
|
||
|--------|------|-----------|------|------|
|
||
| id | UUID | id | PK | 主键 |
|
||
| paymentNo | VARCHAR(30) | payment_no | NOT NULL, UNIQUE | 支付编号(PY + yyyyMMddHHmmss) |
|
||
| billId | UUID | bill_id | NOT NULL | 关联账单 |
|
||
| amount | DECIMAL(12,2) | amount | NOT NULL | 支付金额 |
|
||
| method | VARCHAR(20) | method | NOT NULL | 支付方式枚举 |
|
||
| thirdPartyNo | VARCHAR(100) | third_party_no | -- | 第三方交易号(微信/支付宝) |
|
||
| status | VARCHAR(20) | status | NOT NULL, 默认PENDING | 支付状态枚举 |
|
||
| failReason | VARCHAR(500) | fail_reason | -- | 失败原因 |
|
||
| paymentTime | TIMESTAMP | payment_time | -- | 实际支付时间 |
|
||
| operatorId | UUID | operator_id | -- | 操作人(线下收款时为收费员) |
|
||
| receiptNo | VARCHAR(30) | receipt_no | -- | 收据编号 |
|
||
| remark | VARCHAR(500) | remark | -- | 备注 |
|
||
| createdAt | TIMESTAMP | created_at | NOT NULL | 创建时间 |
|
||
| updatedAt | TIMESTAMP | updated_at | NOT NULL | 更新时间 |
|
||
|
||
**枚举定义**:
|
||
|
||
```java
|
||
public enum PaymentMethod {
|
||
WECHAT("微信支付"),
|
||
ALIPAY("支付宝"),
|
||
CASH("现金"),
|
||
BANK_TRANSFER("银行转账"),
|
||
CARD("刷卡");
|
||
}
|
||
|
||
public enum PaymentStatus {
|
||
PENDING("待支付"),
|
||
SUCCESS("支付成功"),
|
||
FAILED("支付失败"),
|
||
REFUNDED("已退款");
|
||
}
|
||
```
|
||
|
||
**数据库索引**:
|
||
|
||
```sql
|
||
idx_fp_payment_no -- (payment_no) -- UNIQUE约束自带索引
|
||
idx_fp_bill_id -- (bill_id)
|
||
idx_fp_status -- (status, payment_time)
|
||
idx_fp_method -- (method, payment_time)
|
||
idx_fp_operator -- (operator_id, payment_time)
|
||
```
|
||
|
||
**外键关系**:
|
||
|
||
```sql
|
||
fk_fp_bill -- bill_id REFERENCES fin_fee_bill(id)
|
||
```
|
||
|
||
---
|
||
|
||
#### 2.2.4 FeeRefund(退款记录)
|
||
|
||
**目标模块**: module-finance(待创建)
|
||
**目标表**: `fin_fee_refund`
|
||
|
||
| 字段名 | 类型 | 数据库列名 | 约束 | 说明 |
|
||
|--------|------|-----------|------|------|
|
||
| id | UUID | id | PK | 主键 |
|
||
| refundNo | VARCHAR(30) | refund_no | NOT NULL, UNIQUE | 退款编号(RF + yyyyMMddHHmmss) |
|
||
| paymentId | UUID | payment_id | NOT NULL | 关联支付记录 |
|
||
| billId | UUID | bill_id | NOT NULL | 关联账单 |
|
||
| amount | DECIMAL(12,2) | amount | NOT NULL | 退款金额 |
|
||
| reason | VARCHAR(500) | reason | NOT NULL | 退款原因 |
|
||
| status | VARCHAR(20) | status | NOT NULL, 默认PENDING | 退款状态枚举 |
|
||
| applicantId | UUID | applicant_id | NOT NULL | 申请人ID |
|
||
| approverId | UUID | approver_id | -- | 审批人ID |
|
||
| approveTime | TIMESTAMP | approve_time | -- | 审批时间 |
|
||
| approveRemark | VARCHAR(500) | approve_remark | -- | 审批备注 |
|
||
| thirdPartyRefundNo | VARCHAR(100) | third_party_refund_no | -- | 第三方退款单号 |
|
||
| refundTime | TIMESTAMP | refund_time | -- | 实际退款时间 |
|
||
| refundMethod | VARCHAR(20) | refund_method | -- | 退款方式:ORIGINAL/OFFLINE |
|
||
| remark | VARCHAR(500) | remark | -- | 备注 |
|
||
| createdAt | TIMESTAMP | created_at | NOT NULL | 创建时间 |
|
||
| updatedAt | TIMESTAMP | updated_at | NOT NULL | 更新时间 |
|
||
|
||
**枚举定义**:
|
||
|
||
```java
|
||
public enum RefundStatus {
|
||
PENDING("待审批"),
|
||
APPROVED("已审批"),
|
||
REJECTED("已拒绝"),
|
||
REFUNDED("已退款"),
|
||
FAILED("退款失败");
|
||
}
|
||
|
||
public enum RefundMethod {
|
||
ORIGINAL("原路退回"),
|
||
OFFLINE("线下退款");
|
||
}
|
||
```
|
||
|
||
**数据库索引**:
|
||
|
||
```sql
|
||
idx_fr_refund_no -- (refund_no) -- UNIQUE约束自带索引
|
||
idx_fr_payment -- (payment_id)
|
||
idx_fr_bill -- (bill_id)
|
||
idx_fr_status -- (status)
|
||
idx_fr_applicant -- (applicant_id, status)
|
||
```
|
||
|
||
**外键关系**:
|
||
|
||
```sql
|
||
fk_fr_payment -- payment_id REFERENCES fin_fee_payment(id)
|
||
fk_fr_bill -- bill_id REFERENCES fin_fee_bill(id)
|
||
```
|
||
|
||
---
|
||
|
||
### 2.3 实体关系图
|
||
|
||
```
|
||
EnergyMeter (module-mdm) FeeItem (module-finance)
|
||
| |
|
||
v v
|
||
EnergyConsumption ---费用计算---> FeeBill (自动/手动生成)
|
||
(抄表数据) | |
|
||
| +---> FeePayment (支付记录)
|
||
| |
|
||
| v
|
||
| FeeRefund (退款记录)
|
||
|
|
||
+-- sourceType=AUTO, sourceId=EnergyConsumption.id
|
||
```
|
||
|
||
**跨模块引用关系**:
|
||
|
||
- FeeBill.sourceId 可指向 EnergyConsumption.id(按用量计费时)
|
||
- FeeBill.spaceNodeId 引用 mdm_space_node.id
|
||
- FeeBill.ownerId 引用 auth_user.id(业主)
|
||
- FeePayment.operatorId 引用 auth_user.id(收费员)
|
||
- FeeRefund.applicantId / approverId 引用 auth_user.id
|
||
|
||
---
|
||
|
||
## 三、API设计
|
||
|
||
### 3.1 已实现API:能耗管理相关端点
|
||
|
||
**基础路径**: `/api/ops/energy`
|
||
**控制器**: `EnergyController`
|
||
|
||
#### 3.1.1 计量点管理
|
||
|
||
| 方法 | 路径 | 说明 | 请求参数 | 响应类型 |
|
||
|------|------|------|---------|---------|
|
||
| POST | `/meters` | 创建计量点 | EnergyMeter JSON | `ApiResponse<EnergyMeter>` |
|
||
| GET | `/meters` | 查询计量点列表 | projectId(必填), energyType(可选) | `ApiResponse<List<EnergyMeter>>` |
|
||
| GET | `/meters/{id}` | 获取计量点详情 | path: id | `ApiResponse<EnergyMeter>` |
|
||
| PUT | `/meters/{id}` | 更新计量点 | path: id, EnergyMeter JSON | `ApiResponse<EnergyMeter>` |
|
||
| DELETE | `/meters/{id}` | 删除计量点(软删除) | path: id | `ApiResponse<Void>` |
|
||
|
||
#### 3.1.2 能耗记录
|
||
|
||
| 方法 | 路径 | 说明 | 请求参数 | 响应类型 |
|
||
|------|------|------|---------|---------|
|
||
| POST | `/consumption` | 录入能耗数据 | `{meterId, currentReading, recordedBy}` | `ApiResponse<EnergyConsumption>` |
|
||
| GET | `/consumption/{meterId}` | 查询能耗记录 | path: meterId, startDate(可选), endDate(可选) | `ApiResponse<List<EnergyConsumption>>` |
|
||
|
||
#### 3.1.3 能耗统计
|
||
|
||
| 方法 | 路径 | 说明 | 请求参数 | 响应类型 |
|
||
|------|------|------|---------|---------|
|
||
| GET | `/statistics/by-type` | 按类型统计消耗 | projectId, month(yyyy-MM-dd) | `ApiResponse<Map<EnergyType, BigDecimal>>` |
|
||
| GET | `/statistics/unit-consumption` | 单方能耗 | projectId, month(yyyy-MM-dd) | `ApiResponse<BigDecimal>` |
|
||
|
||
---
|
||
|
||
### 3.2 待实现API:收费项目/账单/支付/退款相关端点
|
||
|
||
#### 3.2.1 FeeItemController -- 收费项目管理
|
||
|
||
**基础路径**: `/api/finance/fee-items`
|
||
|
||
| 方法 | 路径 | 说明 | 请求体/参数 | 响应类型 |
|
||
|------|------|------|------------|---------|
|
||
| POST | `/` | 创建收费项目 | FeeItemForm JSON | `ApiResponse<FeeItem>` |
|
||
| GET | `/` | 查询收费项目列表 | projectId(必填), type(可选), status(可选), page, size | `ApiResponse<PageResponse<FeeItem>>` |
|
||
| GET | `/{id}` | 获取收费项目详情 | path: id | `ApiResponse<FeeItem>` |
|
||
| PUT | `/{id}` | 更新收费项目 | path: id, FeeItemForm JSON | `ApiResponse<FeeItem>` |
|
||
| PUT | `/{id}/status` | 启用/禁用收费项目 | `{status: "ENABLED"/"DISABLED"}` | `ApiResponse<Void>` |
|
||
| DELETE | `/{id}` | 删除收费项目 | path: id | `ApiResponse<Void>` |
|
||
|
||
**FeeItemForm**:
|
||
|
||
```json
|
||
{
|
||
"projectId": "UUID",
|
||
"name": "物业费",
|
||
"type": "PROPERTY",
|
||
"billingMethod": "AREA",
|
||
"unitPrice": 3.50,
|
||
"unit": "平方米/月",
|
||
"fixedAmount": null,
|
||
"billDay": 1,
|
||
"dueDay": 15,
|
||
"overdueDay": 5,
|
||
"enableLateFee": true,
|
||
"lateFeeRate": 0.0005,
|
||
"maxLateFee": 500.00,
|
||
"description": "住宅物业费"
|
||
}
|
||
```
|
||
|
||
#### 3.2.2 FeeBillController -- 账单管理
|
||
|
||
**基础路径**: `/api/finance/bills`
|
||
|
||
| 方法 | 路径 | 说明 | 请求体/参数 | 响应类型 |
|
||
|------|------|------|------------|---------|
|
||
| POST | `/` | 手动创建账单 | FeeBillForm JSON | `ApiResponse<FeeBill>` |
|
||
| POST | `/generate` | 按收费项目自动生成账单 | `{projectId, feeItemId, billPeriod}` | `ApiResponse<List<FeeBill>>` |
|
||
| POST | `/generate-batch` | 批量生成账单 | `{projectId, billPeriod, feeItemIds[]}` | `ApiResponse<BatchResult>` |
|
||
| GET | `/` | 查询账单列表 | projectId, ownerId, status, billPeriod, page, size | `ApiResponse<PageResponse<FeeBill>>` |
|
||
| GET | `/{id}` | 获取账单详情 | path: id | `ApiResponse<FeeBill>` |
|
||
| PUT | `/{id}` | 更新账单 | path: id, FeeBillForm JSON | `ApiResponse<FeeBill>` |
|
||
| POST | `/{id}/cancel` | 取消账单 | `{reason}` | `ApiResponse<Void>` |
|
||
| GET | `/overdue` | 查询逾期账单 | projectId, page, size | `ApiResponse<PageResponse<FeeBill>>` |
|
||
| GET | `/statistics` | 账单统计 | projectId, billPeriod | `ApiResponse<BillStatistics>` |
|
||
| GET | `/export` | 导出账单 | projectId, billPeriod, format | `Blob` |
|
||
|
||
**FeeBillForm**:
|
||
|
||
```json
|
||
{
|
||
"feeItemId": "UUID",
|
||
"projectId": "UUID",
|
||
"spaceNodeId": "UUID",
|
||
"ownerId": "UUID",
|
||
"billPeriod": "2026-05",
|
||
"usageAmount": 150.50,
|
||
"usageUnit": "kWh",
|
||
"area": 120.00,
|
||
"amount": 525.00,
|
||
"remark": ""
|
||
}
|
||
```
|
||
|
||
**BillStatistics**:
|
||
|
||
```json
|
||
{
|
||
"totalAmount": 150000.00,
|
||
"paidAmount": 120000.00,
|
||
"unpaidAmount": 30000.00,
|
||
"overdueAmount": 15000.00,
|
||
"lateFeeAmount": 500.00,
|
||
"totalCount": 200,
|
||
"paidCount": 160,
|
||
"unpaidCount": 30,
|
||
"overdueCount": 10
|
||
}
|
||
```
|
||
|
||
#### 3.2.3 FeePaymentController -- 支付管理
|
||
|
||
**基础路径**: `/api/finance/payments`
|
||
|
||
| 方法 | 路径 | 说明 | 请求体/参数 | 响应类型 |
|
||
|------|------|------|------------|---------|
|
||
| POST | `/` | 创建支付记录(线下收款) | PaymentForm JSON | `ApiResponse<FeePayment>` |
|
||
| GET | `/` | 查询支付记录 | billId, ownerId, method, status, startDate, endDate, page, size | `ApiResponse<PageResponse<FeePayment>>` |
|
||
| GET | `/{id}` | 获取支付详情 | path: id | `ApiResponse<FeePayment>` |
|
||
| POST | `/{id}/confirm` | 确认支付 | `{status: "SUCCESS"/"FAILED", failReason}` | `ApiResponse<FeePayment>` |
|
||
| POST | `/online/prepare` | 发起线上支付 | `{billId, method}` | `ApiResponse<PaymentPrepareResult>` |
|
||
| POST | `/online/callback` | 支付回调 | 第三方回调数据 | `ApiResponse<Void>` |
|
||
|
||
**PaymentForm**:
|
||
|
||
```json
|
||
{
|
||
"billId": "UUID",
|
||
"amount": 525.00,
|
||
"method": "CASH",
|
||
"receiptNo": "RCP20260518001",
|
||
"remark": ""
|
||
}
|
||
```
|
||
|
||
#### 3.2.4 FeeRefundController -- 退款管理
|
||
|
||
**基础路径**: `/api/finance/refunds`
|
||
|
||
| 方法 | 路径 | 说明 | 请求体/参数 | 响应类型 |
|
||
|------|------|------|------------|---------|
|
||
| POST | `/` | 申请退款 | RefundForm JSON | `ApiResponse<FeeRefund>` |
|
||
| GET | `/` | 查询退款记录 | billId, status, startDate, endDate, page, size | `ApiResponse<PageResponse<FeeRefund>>` |
|
||
| GET | `/{id}` | 获取退款详情 | path: id | `ApiResponse<FeeRefund>` |
|
||
| POST | `/{id}/approve` | 审批通过 | `{approveRemark}` | `ApiResponse<FeeRefund>` |
|
||
| POST | `/{id}/reject` | 审批拒绝 | `{approveRemark}` | `ApiResponse<FeeRefund>` |
|
||
| POST | `/{id}/execute` | 执行退款 | `{thirdPartyRefundNo, refundMethod}` | `ApiResponse<FeeRefund>` |
|
||
|
||
**RefundForm**:
|
||
|
||
```json
|
||
{
|
||
"paymentId": "UUID",
|
||
"billId": "UUID",
|
||
"amount": 525.00,
|
||
"reason": "重复缴费",
|
||
"refundMethod": "ORIGINAL"
|
||
}
|
||
```
|
||
|
||
#### 3.2.5 FeeReminderJob -- 催缴定时任务
|
||
|
||
| 任务 | Cron表达式 | 说明 |
|
||
|------|-----------|------|
|
||
| 到期提醒 | `0 0 9 * * ?` | 每天上午9点检查3天内到期账单,发送提醒 |
|
||
| 逾期催缴 | `0 0 10 * * ?` | 每天上午10点检查逾期账单,发送催缴通知 |
|
||
| 滞纳金计算 | `0 0 2 * * ?` | 每天凌晨2点计算逾期账单滞纳金 |
|
||
| 周汇总 | `0 0 18 ? * MON` | 每周一18点汇总逾期账单,通知项目经理 |
|
||
|
||
---
|
||
|
||
## 四、业务规则
|
||
|
||
### 4.1 能耗计费规则(已实现 + 待完善)
|
||
|
||
#### 4.1.1 已实现规则
|
||
|
||
| 规则编号 | 规则名称 | 规则描述 | 实现位置 |
|
||
|---------|---------|---------|---------|
|
||
| E-001 | 仪表状态校验 | 只能对ACTIVE状态的仪表进行抄表 | EnergyConsumptionServiceImpl |
|
||
| E-002 | 读数递增校验 | 当前读数不能小于上次读数 | EnergyConsumptionServiceImpl |
|
||
| E-003 | 自动获取上次读数 | 从最近一条记录获取previousReading,首次为0 | EnergyConsumptionServiceImpl |
|
||
| E-004 | 自动计算消耗量 | consumption = currentReading - previousReading | EnergyConsumptionServiceImpl |
|
||
| E-005 | 自动计算费用 | amount = consumption * meter.unitPrice(单价为空时为0) | EnergyConsumptionServiceImpl |
|
||
| E-006 | 按月统计 | 根据month参数计算月份起止日期 | EnergyConsumptionServiceImpl |
|
||
| E-007 | 单方能耗 | 遍历项目所有ACTIVE计量点,累加月度消耗量 | EnergyConsumptionServiceImpl |
|
||
|
||
#### 4.1.2 待修复缺陷
|
||
|
||
| 缺陷编号 | 描述 | 严重度 | 修复方案 |
|
||
|---------|------|--------|---------|
|
||
| E-BUG-001 | getConsumptionByType()将总消耗全部归入LIGHTING | 高 | 按 meter.energyType 真正分项汇总 |
|
||
| E-BUG-002 | 前后端能源类型枚举不一致 | 中 | 统一为后端6种枚举,前端对齐 |
|
||
|
||
---
|
||
|
||
### 4.2 收费项目规则(待设计)
|
||
|
||
| 规则编号 | 规则名称 | 规则描述 | 适用计费方式 |
|
||
|---------|---------|---------|------------|
|
||
| FI-001 | 周期性收费 | 按月/季/年定期出账,billDay指定出账日 | FIXED / AREA / USAGE |
|
||
| FI-002 | 一次性收费 | 临时创建,不参与自动出账 | CUSTOM |
|
||
| FI-003 | 临时收费 | 针对特定业主的临时性收费 | CUSTOM |
|
||
| FI-004 | 固定金额计费 | 每期收取固定金额(如停车费300元/月) | FIXED |
|
||
| FI-005 | 按面积计费 | 面积 * 单价(如物业费3.5元/平方米/月) | AREA |
|
||
| FI-006 | 按用量计费 | 用量 * 单价(如电费0.85元/kWh),对接能耗数据 | USAGE |
|
||
| FI-007 | 编码自动生成 | 格式:FI + yyyyMMddHHmmss,冲突时追加后缀 | 全部 |
|
||
| FI-008 | 禁用不删除 | 收费项目禁用后不再参与自动出账,已有账单不受影响 | 全部 |
|
||
| FI-009 | 项目隔离 | 收费项目属于特定项目,跨项目不可见 | 全部 |
|
||
|
||
---
|
||
|
||
### 4.3 账单生成规则(待设计)
|
||
|
||
| 规则编号 | 规则名称 | 规则描述 |
|
||
|---------|---------|---------|
|
||
| BL-001 | 自动生成 | 根据收费项目的billDay,定时任务自动为项目下所有业主生成账单 |
|
||
| BL-002 | 手动生成 | 管理员手动为指定业主创建账单 |
|
||
| BL-003 | 批量生成 | 一次性为项目所有业主生成某类收费项目的账单 |
|
||
| BL-004 | 账单编号生成 | 格式:BL + yyyyMMdd + 4位序号,序号按天递增 |
|
||
| BL-005 | 到期日计算 | dueDate = billDate + feeItem.dueDay天 |
|
||
| BL-006 | 逾期日计算 | overdueDate = dueDate + feeItem.overdueDay天 |
|
||
| BL-007 | 按用量计费账单 | 从EnergyConsumption获取当期用量,计算金额 |
|
||
| BL-008 | 按面积计费账单 | 从SpaceNode获取面积,计算金额 = 面积 * 单价 |
|
||
| BL-009 | 固定金额账单 | 金额 = feeItem.fixedAmount |
|
||
| BL-010 | 防重复生成 | 同一收费项目 + 同一业主 + 同一账期不可重复生成 |
|
||
| BL-011 | 催缴提醒 | 到期前3天发送提醒,逾期后发送催缴通知 |
|
||
| BL-012 | 账单取消 | 已支付/部分支付的账单不可取消,需先退款 |
|
||
|
||
---
|
||
|
||
### 4.4 支付流程(待设计)
|
||
|
||
| 规则编号 | 规则名称 | 规则描述 |
|
||
|---------|---------|---------|
|
||
| PY-001 | 线下收款 | 管理员登记现金/转账/刷卡收款,直接确认成功 |
|
||
| PY-002 | 线上支付 | 调用微信/支付宝SDK生成预支付单,等待回调确认 |
|
||
| PY-003 | 支付确认 | 线上支付由回调确认,线下支付由操作员确认 |
|
||
| PY-004 | 部分支付 | 支持部分支付,账单状态变为PARTIAL_PAID |
|
||
| PY-005 | 超额支付 | 支付金额不可超过应付金额(payableAmount - paidAmount) |
|
||
| PY-006 | 支付编号生成 | 格式:PY + yyyyMMddHHmmss |
|
||
| PY-007 | 账单状态联动 | 支付成功后更新账单paidAmount和status |
|
||
| PY-008 | 收据编号 | 线下收款时生成收据编号 |
|
||
|
||
**支付状态流转**:
|
||
|
||
```
|
||
PENDING --(支付成功)--> SUCCESS
|
||
PENDING --(支付失败)--> FAILED
|
||
SUCCESS --(发起退款)--> REFUNDED
|
||
```
|
||
|
||
**账单状态联动**:
|
||
|
||
```
|
||
UNPAID --(部分支付)--> PARTIAL_PAID
|
||
UNPAID/PARTIAL_PAID --(全额支付)--> PAID
|
||
UNPAID --(超过逾期日)--> OVERDUE
|
||
任意状态 --(取消)--> CANCELLED(需先退款)
|
||
```
|
||
|
||
---
|
||
|
||
### 4.5 退款流程(待设计)
|
||
|
||
| 规则编号 | 规则名称 | 规则描述 |
|
||
|---------|---------|---------|
|
||
| RF-001 | 退款申请 | 业主或管理员发起退款申请,需指定退款原因 |
|
||
| RF-002 | 退款金额限制 | 退款金额不可超过原支付金额 |
|
||
| RF-003 | 退款审批 | 退款金额 > 1000元需审批,否则自动通过 |
|
||
| RF-004 | 审批通过 | 审批人确认后,退款状态变为APPROVED |
|
||
| RF-005 | 审批拒绝 | 审批人可拒绝退款,需填写拒绝原因 |
|
||
| RF-006 | 原路退回 | 线上支付的退款原路退回至支付账户 |
|
||
| RF-007 | 线下退款 | 现金/转账支付的退款通过线下处理 |
|
||
| RF-008 | 退款执行 | 记录第三方退款单号和实际退款时间 |
|
||
| RF-009 | 账单金额回退 | 退款成功后,账单paidAmount减少,状态可能回退 |
|
||
| RF-010 | 退款编号生成 | 格式:RF + yyyyMMddHHmmss |
|
||
|
||
**退款状态流转**:
|
||
|
||
```
|
||
PENDING --(审批通过)--> APPROVED
|
||
PENDING --(审批拒绝)--> REJECTED
|
||
APPROVED --(退款成功)--> REFUNDED
|
||
APPROVED --(退款失败)--> FAILED
|
||
```
|
||
|
||
---
|
||
|
||
### 4.6 滞纳金计算(待设计)
|
||
|
||
| 规则编号 | 规则名称 | 规则描述 |
|
||
|---------|---------|---------|
|
||
| LF-001 | 计算触发 | 每天凌晨2点定时任务检查逾期账单 |
|
||
| LF-002 | 计算公式 | lateFee = 逾期天数 * payableAmount * lateFeeRate |
|
||
| LF-003 | 逾期天数 | 从overdueDate开始计算,到当前日期 |
|
||
| LF-004 | 上限控制 | lateFee不超过feeItem.maxLateFee |
|
||
| LF-005 | 累加计算 | 每天累加,不覆盖之前的滞纳金 |
|
||
| LF-006 | 前提条件 | 仅当feeItem.enableLateFee = true时计算 |
|
||
| LF-007 | 已支付账单 | 已全额支付的账单不再计算滞纳金 |
|
||
| LF-008 | 已取消账单 | 已取消的账单不再计算滞纳金 |
|
||
| LF-009 | 部分支付 | 滞纳金基于剩余应付金额计算 |
|
||
|
||
**滞纳金计算示例**:
|
||
|
||
```
|
||
假设:
|
||
payableAmount = 1000元
|
||
lateFeeRate = 0.0005(万分之五/天)
|
||
maxLateFee = 500元
|
||
overdueDate = 2026-05-10
|
||
当前日期 = 2026-05-18
|
||
|
||
计算:
|
||
逾期天数 = 8天
|
||
每日滞纳金 = 1000 * 0.0005 = 0.5元
|
||
累计滞纳金 = 8 * 0.5 = 4元(未超过上限500元)
|
||
```
|
||
|
||
---
|
||
|
||
## 五、执行约束
|
||
|
||
| 约束编号 | 约束名称 | 约束描述 |
|
||
|---------|---------|---------|
|
||
| CON-001 | 金额精度 | 所有金额字段使用DECIMAL(12,2),单价使用DECIMAL(12,4),利率使用DECIMAL(8,6) |
|
||
| CON-002 | 事务一致性 | 账单生成、支付确认、退款执行必须在同一事务中完成账单状态更新 |
|
||
| CON-003 | 并发控制 | 支付操作使用乐观锁(version字段或状态校验),防止重复支付 |
|
||
| CON-004 | 审计日志 | 所有收费/支付/退款操作必须记录审计日志 |
|
||
| CON-005 | 项目隔离 | 所有查询必须按projectId过滤,确保项目间数据隔离 |
|
||
| CON-006 | 软删除 | 收费项目使用启用/禁用替代物理删除,账单/支付/退款不允许删除 |
|
||
| CON-007 | 编码唯一性 | billNo/paymentNo/refundNo全局唯一,生成时需处理冲突 |
|
||
| CON-008 | 定时任务幂等 | 催缴/滞纳金计算任务必须幂等,重复执行不产生副作用 |
|
||
|
||
---
|
||
|
||
## 六、权限控制
|
||
|
||
| 权限编码 | 权限名称 | 适用角色 | 说明 |
|
||
|---------|---------|---------|------|
|
||
| finance:fee-item:list | 查看收费项目 | 项目管理员/财务人员 | 查看项目下收费项目列表 |
|
||
| finance:fee-item:create | 创建收费项目 | 系统管理员 | 创建新的收费项目 |
|
||
| finance:fee-item:update | 修改收费项目 | 系统管理员 | 修改收费项目配置 |
|
||
| finance:fee-item:delete | 删除收费项目 | 系统管理员 | 删除/禁用收费项目 |
|
||
| finance:bill:list | 查看账单 | 项目管理员/财务人员 | 查看项目下账单列表 |
|
||
| finance:bill:create | 创建账单 | 财务人员 | 手动创建账单 |
|
||
| finance:bill:generate | 生成账单 | 财务人员 | 自动/批量生成账单 |
|
||
| finance:bill:cancel | 取消账单 | 财务主管 | 取消账单(需审批) |
|
||
| finance:bill:export | 导出账单 | 财务人员 | 导出账单Excel/PDF |
|
||
| finance:payment:create | 登记收款 | 财务人员 | 线下收款登记 |
|
||
| finance:payment:confirm | 确认支付 | 财务人员 | 确认支付状态 |
|
||
| finance:payment:list | 查看支付记录 | 财务人员 | 查看支付记录列表 |
|
||
| finance:refund:apply | 申请退款 | 财务人员/业主 | 发起退款申请 |
|
||
| finance:refund:approve | 审批退款 | 财务主管 | 审批退款申请 |
|
||
| finance:refund:execute | 执行退款 | 财务人员 | 执行退款操作 |
|
||
| finance:refund:list | 查看退款记录 | 财务人员 | 查看退款记录列表 |
|
||
| finance:statistics:view | 查看财务统计 | 项目管理员/财务主管 | 查看财务报表 |
|
||
| finance:late-fee:config | 配置滞纳金 | 系统管理员 | 配置滞纳金规则 |
|
||
|
||
**数据级权限**:
|
||
|
||
- 财务人员(PROJECT数据范围):只能查看/操作所属项目的财务数据
|
||
- 财务主管(ALL数据范围):可查看所有项目的财务数据
|
||
- 业主(SELF数据范围):只能查看自己的账单和支付记录
|
||
|
||
---
|
||
|
||
## 七、例外情况处理
|
||
|
||
| 例外编号 | 例外场景 | 处理策略 | 错误码 |
|
||
|---------|---------|---------|--------|
|
||
| EX-001 | 重复生成账单 | 检查feeItemId + ownerId + billPeriod唯一性,已存在则跳过 | 7001 |
|
||
| EX-002 | 支付金额超过应付金额 | 校验支付金额 <= payableAmount - paidAmount | 7002 |
|
||
| EX-003 | 已支付账单取消 | 拒绝取消,提示需先退款 | 7003 |
|
||
| EX-004 | 退款金额超过支付金额 | 校验退款金额 <= 原支付金额 | 7004 |
|
||
| EX-005 | 重复支付 | 状态校验,已支付/已退款的支付记录不可再次确认 | 7005 |
|
||
| EX-006 | 能耗数据缺失 | 按用量计费时无对应能耗记录,生成0元账单并标记异常 | 7006 |
|
||
| EX-007 | 业主无关联房产 | 生成账单时业主无房产关联,跳过并记录日志 | 7007 |
|
||
| EX-008 | 线上支付超时 | 支付状态保持PENDING,由对账任务处理 | 7008 |
|
||
| EX-009 | 线上支付回调异常 | 记录原始回调数据,人工介入处理 | 7009 |
|
||
| EX-010 | 滞纳金计算溢出 | lateFee不超过maxLateFee上限 | 7010 |
|
||
| EX-011 | 收费项目被禁用后自动出账 | 跳过已禁用的收费项目 | 7011 |
|
||
| EX-012 | 批量生成部分失败 | 记录成功/失败数量和失败原因,返回BatchResult | 7012 |
|