12 KiB
12 KiB
财务计费领域技术方案
领域编号: 4.4
微服务: ether-finance
最后更新: 2026-02-10
一、领域概述
1.1 领域职责
财务计费领域负责物业费用管理全生命周期:
- 收费项目管理(物业费、停车费、水电费等)
- 账单生成与管理
- 支付处理与对账
- 费用催缴通知
- 财务报表与统计
1.2 核心概念
| 概念 | 说明 | 对应实体 |
|---|---|---|
| 收费项目 | 可收费的项目定义 | FeeItem |
| 账单 | 应收费用单据 | FeeBill |
| 支付记录 | 支付流水记录 | FeePayment |
| 退款 | 退款申请与处理 | FeeRefund |
二、领域模型
2.1 聚合根设计
FeeItem(收费项目)
@Entity
@Table(name = "fin_fee_item")
@Data
public class FeeItem {
@Id
private UUID id;
private UUID projectId;
private String code; // 项目编码
private String name; // 项目名称
private FeeType type; // PROPERTY/PARKING/WATER/ELECTRICITY/GAS/OTHER
// 计费规则
private BillingMethod billingMethod; // FIXED/AREA/USAGE/CUSTOM
private BigDecimal unitPrice; // 单价
private String unit; // 单位: 元/月、元/㎡·月、元/度
// 账期
private Integer billDay; // 账单日(每月几号)
private Integer dueDay; // 到期日(每月几号)
private Integer overdueDay; // 逾期日(每月几号)
// 滞纳金
private Boolean enableLateFee;
private BigDecimal lateFeeRate; // 滞纳金比例(日利率)
private BigDecimal maxLateFee; // 滞纳金上限
// 状态
private Boolean enabled;
// 审计字段
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
// 收费类型枚举
public enum FeeType {
PROPERTY("物业费"),
PARKING("停车费"),
WATER("水费"),
ELECTRICITY("电费"),
GAS("燃气费"),
HEATING("供暖费"),
REPAIR_FUND("维修基金"),
OTHER("其他");
}
// 计费方式枚举
public enum BillingMethod {
FIXED("固定金额"),
AREA("按面积"),
USAGE("按用量"),
CUSTOM("自定义");
}
FeeBill(收费账单)
@Entity
@Table(name = "fin_fee_bill")
@Data
public class FeeBill {
@Id
private UUID id;
private UUID projectId;
private String billNo; // 账单编号
// 关联信息
private UUID feeItemId; // 收费项目
private UUID spaceNodeId; // 关联房产
private UUID ownerId; // 关联业主
// 账期
private String billPeriod; // 账期: 2024-02
private LocalDate billDate; // 账单日期
private LocalDate dueDate; // 到期日期
private LocalDate overdueDate; // 逾期日期
// 用量(按用量计费)
private BigDecimal usageAmount; // 用量
private String usageUnit; // 用量单位
// 金额
private BigDecimal amount; // 应收金额
private BigDecimal lateFee; // 滞纳金
private BigDecimal discount; // 优惠金额
private BigDecimal payableAmount; // 应付金额 = amount + lateFee - discount
private BigDecimal paidAmount; // 已付金额
// 状态
private BillStatus status; // UNPAID/PARTIAL_PAID/PAID/OVERDUE/CANCELLED
// 关联支付记录
@OneToMany(mappedBy = "bill")
private List<FeePayment> payments;
// 审计字段
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
// 账单状态枚举
public enum BillStatus {
UNPAID("未缴费"),
PARTIAL_PAID("部分缴费"),
PAID("已缴费"),
OVERDUE("已逾期"),
CANCELLED("已取消");
}
FeePayment(支付记录)
@Entity
@Table(name = "fin_fee_payment")
@Data
public class FeePayment {
@Id
private UUID id;
private UUID billId;
private String paymentNo; // 支付流水号
private BigDecimal amount; // 支付金额
// 支付方式
private PaymentMethod method; // WECHAT/ALIPAY/CASH/BANK_TRANSFER/CARD
private String thirdPartyNo; // 第三方支付流水号
// 支付状态
private PaymentStatus status; // PENDING/SUCCESS/FAILED/REFUNDED
private String failReason; // 失败原因
// 时间
private LocalDateTime paymentTime;
private String remark;
// 操作人
private UUID operatorId;
private String operatorName;
// 审计字段
private LocalDateTime createdAt;
}
// 支付方式枚举
public enum PaymentMethod {
WECHAT("微信支付"),
ALIPAY("支付宝"),
CASH("现金"),
BANK_TRANSFER("银行转账"),
CARD("刷卡");
}
FeeRefund(退款记录)
@Entity
@Table(name = "fin_fee_refund")
@Data
public class FeeRefund {
@Id
private UUID id;
private UUID projectId;
private UUID billId;
private UUID paymentId; // 关联支付记录
private String refundNo; // 退款单号
private BigDecimal amount; // 退款金额
private String reason; // 退款原因
// 状态
private RefundStatus status; // PENDING/APPROVED/REJECTED/REFUNDED
// 审批
private UUID approverId;
private String approverName;
private LocalDateTime approveTime;
private String approveRemark;
// 退款执行
private String thirdPartyRefundNo;
private LocalDateTime refundTime;
// 审计字段
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
三、费用催缴
3.1 定时任务
@Component
public class FeeReminderJob {
@Autowired
private FeeBillRepository feeBillRepository;
@Autowired
private NotificationService notificationService;
// 每天9点执行:提醒即将到期
@Scheduled(cron = "0 0 9 * * ?")
public void remindUpcomingDue() {
// 查询3天内到期的账单
LocalDate targetDate = LocalDate.now().plusDays(3);
List<FeeBill> upcomingBills = feeBillRepository
.findByDueDateBetweenAndStatus(LocalDate.now(), targetDate, BillStatus.UNPAID);
for (FeeBill bill : upcomingBills) {
notificationService.sendFeeReminder(bill, "FEE_UPCOMING_DUE");
}
}
// 每天9点和18点执行:催缴逾期
@Scheduled(cron = "0 0 9,18 * * ?")
public void remindOverdue() {
// 查询已逾期的账单
List<FeeBill> overdueBills = feeBillRepository
.findByOverdueDateBeforeAndStatus(LocalDate.now(), BillStatus.UNPAID);
for (FeeBill bill : overdueBills) {
// 计算滞纳金
calculateLateFee(bill);
notificationService.sendFeeReminder(bill, "FEE_OVERDUE");
}
}
// 每周一9点执行:发送汇总
@Scheduled(cron = "0 0 9 ? * MON")
public void sendWeeklySummary() {
// 发送本周待缴费汇总
}
private void calculateLateFee(FeeBill bill) {
if (!bill.getEnableLateFee()) {
return;
}
// 计算逾期天数
long overdueDays = ChronoUnit.DAYS.between(bill.getOverdueDate(), LocalDate.now());
if (overdueDays <= 0) {
return;
}
// 计算滞纳金
BigDecimal lateFee = bill.getAmount()
.multiply(bill.getLateFeeRate())
.multiply(BigDecimal.valueOf(overdueDays));
// 不超过上限
if (bill.getMaxLateFee() != null && lateFee.compareTo(bill.getMaxLateFee()) > 0) {
lateFee = bill.getMaxLateFee();
}
bill.setLateFee(lateFee);
bill.setPayableAmount(bill.getAmount().add(lateFee).subtract(bill.getDiscount()));
feeBillRepository.save(bill);
}
}
四、实现状态与差异
4.1 实现状态
| 功能模块 | 实现状态 | 备注 |
|---|---|---|
| FeeItem | 🟢 已实现 | 基础CRUD |
| FeeBill | 🟢 已实现 | 基础CRUD |
| FeePayment | 🟢 已实现 | 基础CRUD |
| 费用催缴 | 🟢 已实现 | 定时任务 |
| 滞纳金计算 | 🟢 已实现 | 自动计算 |
| 退款功能 | 🔴 未实现 | 待开发 |
| 财务报表 | 🔴 未实现 | 待开发 |
| 支付网关 | 🔴 未实现 | 待对接 |
4.2 与设计方案的差异
| 设计项 | 设计方案 | 现有实现 | 差异分析 |
|---|---|---|---|
| 实体归属 | ether-finance | ether-finance + ether-mdm重复 | ❌ 存在重复实体 |
| 支付网关 | 对接微信/支付宝 | 未对接 | 🔴 功能缺失 |
| 退款 | 退款流程 | 未实现 | 🔴 功能缺失 |
4.3 改进计划
| 优先级 | 改进项 | 说明 |
|---|---|---|
| P1 | 清理重复实体 | 删除ether-mdm中的Fee相关实体 |
| P2 | 实现退款功能 | 退款申请、审批、执行流程 |
| P2 | 对接支付网关 | 集成微信支付、支付宝SDK |
| P2 | 财务报表 | 收费统计、欠费分析、收入趋势 |
五、数据库表结构
-- 收费项目表
CREATE TABLE fin_fee_item (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
code VARCHAR(50) NOT NULL,
name VARCHAR(100) NOT NULL,
type VARCHAR(20) NOT NULL,
billing_method VARCHAR(20) NOT NULL,
unit_price NUMERIC(12,2),
unit VARCHAR(20),
bill_day INTEGER,
due_day INTEGER,
overdue_day INTEGER,
enable_late_fee BOOLEAN DEFAULT FALSE,
late_fee_rate NUMERIC(5,4),
max_late_fee NUMERIC(12,2),
enabled BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
UNIQUE(project_id, code)
);
-- 账单表
CREATE TABLE fin_fee_bill (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
bill_no VARCHAR(32) NOT NULL,
fee_item_id UUID NOT NULL,
space_node_id UUID,
owner_id UUID,
bill_period VARCHAR(10) NOT NULL,
bill_date DATE NOT NULL,
due_date DATE NOT NULL,
overdue_date DATE,
usage_amount NUMERIC(12,2),
usage_unit VARCHAR(20),
amount NUMERIC(12,2) NOT NULL,
late_fee NUMERIC(12,2) DEFAULT 0,
discount NUMERIC(12,2) DEFAULT 0,
payable_amount NUMERIC(12,2) NOT NULL,
paid_amount NUMERIC(12,2) DEFAULT 0,
status VARCHAR(20) NOT NULL DEFAULT 'UNPAID',
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
UNIQUE(project_id, bill_no)
);
-- 支付记录表
CREATE TABLE fin_fee_payment (
id UUID PRIMARY KEY,
bill_id UUID NOT NULL,
payment_no VARCHAR(64) NOT NULL,
amount NUMERIC(12,2) NOT NULL,
method VARCHAR(20) NOT NULL,
third_party_no VARCHAR(100),
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
fail_reason VARCHAR(500),
payment_time TIMESTAMP,
remark VARCHAR(500),
operator_id UUID,
operator_name VARCHAR(100),
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 退款记录表
CREATE TABLE fin_fee_refund (
id UUID PRIMARY KEY,
project_id UUID NOT NULL,
bill_id UUID NOT NULL,
payment_id UUID NOT NULL,
refund_no VARCHAR(64) NOT NULL,
amount NUMERIC(12,2) NOT NULL,
reason VARCHAR(500),
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
approver_id UUID,
approver_name VARCHAR(100),
approve_time TIMESTAMP,
approve_remark VARCHAR(500),
third_party_refund_no VARCHAR(100),
refund_time TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- 创建索引
CREATE INDEX idx_fee_item_project ON fin_fee_item(project_id);
CREATE INDEX idx_fee_bill_project ON fin_fee_bill(project_id);
CREATE INDEX idx_fee_bill_status ON fin_fee_bill(status);
CREATE INDEX idx_fee_bill_owner ON fin_fee_bill(owner_id);
CREATE INDEX idx_fee_bill_due_date ON fin_fee_bill(due_date);
CREATE INDEX idx_fee_payment_bill ON fin_fee_payment(bill_id);
文档维护: 本领域技术方案由 ether-finance 服务负责人维护