6.2 KiB
6.2 KiB
title, aliases, tags, audience, status, sub_feature, last_review, code_version
| title | aliases | tags | audience | status | sub_feature | last_review | code_version | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| prop-acc · meter · 计量表与抄表流水 |
|
|
|
已发布 | meter | 2026-05-25 | 2026-05-22 |
计量表与抄表流水
计量表模块底层是两个对象配合:Meter(物理表的配置)+ MeterReading(每次抄表的不可变流水)。模式上与 ../deposit/deposit-account-vs-transaction同构,但对象的物理性让它有几条独特特征:
- 每张表是真实硬件(电表 / 水表 / 燃气表),挂在具体房屋(
asset_id)上 - 不直接产收据 —— 抄表产
Bill,后续业户付账单再走 ../adhoc/collection-order-and-receipt - 没有"账户余额"概念(没有 balance 字段),业户余额追踪在 ../prepaid/prepaid-account-vs-transaction
为什么用双对象
[!info] 类比:实体水表
- Meter = 表面板,上面写编号、安装时间、倍率
- MeterReading = 每次抄表的本子记录:几号几月几日读了多少、谁抄的、有没有拍照
如果只有 Meter 没有 Reading → 不知道每月用了多少,无法算账单。 如果只有 Reading 没有 Meter → 不知道表的物理属性(倍率、装在哪、什么费用),Reading 是孤立数字。
所以两个都要。
字段速查
Meter(计量表)
| 字段 | 含义 |
|---|---|
id |
表 ID |
community_id |
所属物业项目 |
asset_id |
绑定的房屋资产(必填,通过 asset 找业户) |
fee_type_id |
费用类型(水费 / 电费 / 燃气费,决定单价) |
replaced_meter_id |
上一代表(null = 原生新表,见 replacement-chain) |
code |
表编号(物理表牌号,通常物业自编) |
multiplier |
倍率(decimal(10,4),工业表 10/100/1000) |
initial_reading |
初始读数(decimal(12,2)) |
is_active |
是否在役 |
installed_at |
安装日期 |
decommissioned_at |
退役日期(null = 在役) |
decommission_reason |
退役原因(5 种枚举,详见 decommission-and-locking) |
final_reading |
退役时最终读数 |
MeterReading(抄表流水)
| 字段 | 含义 |
|---|---|
id |
流水 ID |
meter_id |
归属表 |
read_at |
抄表日期 |
current_reading |
本次读数(物理表头数字) |
previous_reading |
上次读数(自动从最近一条 reading 取) |
consumption |
用量(=(current - previous) × multiplier,自动算) |
source |
来源:manual(手抄) / remote(集抄,详见 reading-source-and-photo-proof) |
photo_url |
拍照存证 URL(可选 / 集抄无) |
operated_by |
抄表员 ID(manual 类型必填) |
bill_id |
关联生成的账单(若已生成 Bill,null = 未生成) |
memo |
备注 |
| 创建后不可变 | 一旦生成只读;若 bill_id != null 更不可改(双锁) |
两者的契约
- 每张 Meter 可有多条 MeterReading(理想情况是每月一条)
- MeterReading 必属于一张 Meter(
meter_idNOT NULL) - 最新 reading 的 current_reading = 该 meter 的"当前累计读数"(Meter 自身不存 current,从 reading 推出)
- consumption = (current - previous) × multiplier:倍率乘进去就是真实用量(度 / 吨 / 立方米)
与"账户+流水"型模块的本质差异
| 维度 | Account + Transaction(deposit / prepaid) | Meter + MeterReading |
|---|---|---|
| 主对象表达什么 | 账户余额 | 物理表的配置 |
| 流水表达什么 | 资金变动(deposit / refund / consume) | 抄表读数(用量计算源) |
| 主对象有 balance 吗 | ✅ 有 | ❌ 无(余额是用量,在 Reading 里) |
| 流水方向 | + / -(余额加减) | 无方向(只有"本月读了多少") |
| 自动关账 | 看模块(deposit 自动,prepaid 不) | 走"退役 (decommission)" 不是"关账" |
| 写入操作种类 | 多种(deposit / consume / refund / forfeit) | 单一(抄表 record_reading)+ 换表 / 退役 |
| 直接产 Receipt | 是 | 否,通过 Bill 中转 |
业户视角
业户通常不直接接触 Meter / MeterReading 概念。看到的是:
- 月底物业 App 推送账单"5 月电费 ¥168,用电 280 度"
- 收据"水费 ¥54"
- 偶尔小程序"我的计量"页可查看本月用量趋势(若开启)
底下的 Meter 和 MeterReading 是后台运营的事。唯一会接触的:业户对账单金额有异议时,可申请看历次抄表记录(系统应能展示该业户表的全部 reading 历史)。
抄表员视角
李师傅是物业聘的抄表员,每月固定时间挨家挨户(或集中点位)读表头数字:
- 用物业 App / 抄表机 录入 → 系统建 MeterReading(
source=manual,operated_by=李师傅) - 拍照可选(详见 reading-source-and-photo-proof)
- 如果该社区接入集抄系统(IoT 表),系统自动生成 reading(
source=remote),李师傅不用跑
业务人员视角
物业财务的工作:
- 看
MeterDashboard:本月待抄表清单、高用量异常、按费用类型用量走势 - 录入 / 校验 reading(若有异议)
- 触发
GenerateBillsFromMeterReadingsAction→ 自动生成所有未结账的 reading 对应的 Bill - 月底对账:每张 reading 是否都有对应 Bill,有 Bill 是否已 Paid
系统视角:Bill 生成是单独一步
flowchart LR
A[抄表员录入 MeterReading] -.第一步.-> B[MeterReading<br/>bill_id=null]
B -->|GenerateBillsFromMeterReadingsAction| C[Bill 生成<br/>+ MeterReading.bill_id 回写]
C -.业户付账单.-> D[CollectionOrder + Receipt<br/>付款方式可选现金/微信/预存款]
关键:MeterReading 不直接产 CollectionOrder + Receipt。要先经过 Bill 生成步骤(可能是月底批量,可能是抄表后立即),然后业户付账单才走收款流程。计量表是计费源,不是收款源。