vault backup: 2026-05-26 00:13:05
This commit is contained in:
234
prop-acc/scenarios/meter/replace-broken-meter.md
Normal file
234
prop-acc/scenarios/meter/replace-broken-meter.md
Normal file
@@ -0,0 +1,234 @@
|
||||
---
|
||||
title: prop-acc · meter · 场景 - 换表:旧表故障/退役,新表带 -R1 后缀
|
||||
aliases:
|
||||
- 换表
|
||||
- 表更换
|
||||
- replace-broken-meter
|
||||
- ReplaceMeterAction
|
||||
- 场景-换计量表
|
||||
tags:
|
||||
- 场景
|
||||
- prop-acc
|
||||
- 计量表
|
||||
- 表管理
|
||||
audience:
|
||||
- 业务人员
|
||||
- 抄表员
|
||||
status: 已发布
|
||||
sub_feature: meter
|
||||
last_review: 2026-05-26
|
||||
code_version: 2026-05-22
|
||||
---
|
||||
|
||||
# 场景:换表,旧表故障/退役,新表带 -R1 后缀
|
||||
|
||||
物理表**老化 / 损坏 / 校验未过**,需要换新表。系统通过 `ReplaceMeterAction` **一步完成**:旧表退役 + 新表建立 + `replaced_meter_id` 关联 + 初始读数继承。新表自动编号 `<旧编号>-R1`。
|
||||
|
||||
## 典型情境
|
||||
|
||||
> [!example] 真实情境
|
||||
> 张阿姨家电表(编号 E-501)用了 8 年,2026 年 5 月例行校验未通过(读数漂移),物业要换新表。
|
||||
>
|
||||
> 换表当天:
|
||||
> - 抄表员李师傅现场读旧表:**5000 度**
|
||||
> - 卸下旧表 + 装上新表
|
||||
> - 新表出厂读数:**0**(物理上)
|
||||
> - 系统操作:`ReplaceMeterAction`
|
||||
>
|
||||
> 系统结果:
|
||||
> - 旧表 E-501:`is_active=false`, `decommissioned_at=今天`, `decommission_reason=Replaced`, `final_reading=5000`
|
||||
> - 新表 **E-501-R1**:`is_active=true`, `installed_at=今天`, `replaced_meter_id=旧表 ID`, **`initial_reading=5000`(继承)**, multiplier 继承
|
||||
|
||||
## 抄表员视角(李师傅)
|
||||
|
||||
### 第 1 步:现场操作
|
||||
|
||||
到张阿姨家:
|
||||
|
||||
1. 检查旧表状态(确认换表必要性)
|
||||
2. **拍照存证**旧表当前读数(关键!后续争议时凭证)
|
||||
3. 物理换表(断电 → 换表 → 通电)
|
||||
4. 拍照新表初始状态(出厂 0)
|
||||
5. 把信息回传业务人员(微信 / App / 当面)
|
||||
|
||||
> [!warning] 拍照不能省
|
||||
> 旧表读数没拍照 = 系统里填的"5000" 没物理证据 = 业户事后质疑"我家明明只用了 4500" 时物业百口莫辩。
|
||||
|
||||
### 第 2 步:报回业务
|
||||
|
||||
抄表员把信息汇总给王主管(业务人员):
|
||||
|
||||
- 旧表编号:E-501
|
||||
- 旧表最后读数:5000
|
||||
- 换表日期:2026-05-26
|
||||
- 退役原因:校验未过(`Replaced`)
|
||||
- 新表型号:同型号(multiplier=1)
|
||||
|
||||
## 业务人员视角
|
||||
|
||||
### 第 1 步:打开旧表
|
||||
|
||||
后台 → 计量表 → 找 E-501 → 进 `ViewMeter`。
|
||||
|
||||
### 第 2 步:点 `ReplaceMeterAction`
|
||||
|
||||
右上角"换表"按钮(标签可能是"更换")。
|
||||
|
||||
> [!warning] 按钮可见性
|
||||
> 守护:`is_active=true` + Policy `->authorize('replace')`。已退役表此按钮灰化。
|
||||
|
||||
Modal 表单:
|
||||
|
||||
| 字段 | 填什么 |
|
||||
|---|---|
|
||||
| **旧表最后读数(`final_reading`)** | 5000(抄表员现场读)|
|
||||
| **退役原因(`decommission_reason`)** | `Replaced`(其他 4 种见 [[decommission-and-locking]]) |
|
||||
| **退役日期** | 2026-05-26(默认今天)|
|
||||
| **新表编号** | E-501-R1(系统自动生成,`nextReplacementCode()`,可改但不推荐)|
|
||||
| **新表 multiplier** | 1.0(默认继承旧表)|
|
||||
| **新表安装日期** | 2026-05-26(默认今天)|
|
||||
| 备注 | "校验未通过,换新表" |
|
||||
|
||||
### 第 3 步:提交
|
||||
|
||||
系统在**一个事务**内:
|
||||
|
||||
1. 校验旧表 `is_active=true`(否则按钮就不该出现)
|
||||
2. 旧表 update:
|
||||
- `is_active = false`
|
||||
- `decommissioned_at = 2026-05-26`
|
||||
- `decommission_reason = Replaced`
|
||||
- `final_reading = 5000`
|
||||
3. 建新表:
|
||||
- `code = E-501-R1`(`nextReplacementCode($oldCode)`)
|
||||
- `is_active = true`
|
||||
- `installed_at = 2026-05-26`
|
||||
- `replaced_meter_id = 旧表 ID`
|
||||
- **`initial_reading = 5000`**(继承自旧表 final_reading)
|
||||
- `multiplier = 1.0`(继承)
|
||||
- `community_id` / `asset_id` / `fee_type_id` 继承
|
||||
|
||||
### 第 4 步:验证 + 通知
|
||||
|
||||
后台 → 计量表 → 看新旧两张表 → 确认数据正确。
|
||||
|
||||
业户可不通知(业户对系统层无感)。
|
||||
|
||||
## 系统流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 抄表员
|
||||
participant 王主管
|
||||
participant Filament
|
||||
participant ReplaceMeterAction
|
||||
participant 数据库
|
||||
|
||||
抄表员->>抄表员: 现场拍照 + 换表(物理)
|
||||
抄表员->>王主管: 旧表读数 5000,换表完成
|
||||
|
||||
王主管->>Filament: ViewMeter(旧表) → ReplaceMeterAction
|
||||
Filament->>ReplaceMeterAction: handle(oldMeter, finalReading=5000, reason=Replaced)
|
||||
ReplaceMeterAction->>数据库: 开启事务
|
||||
ReplaceMeterAction->>数据库: 1. 旧表 update:is_active=false, decommissioned_at, decommission_reason=Replaced, final_reading=5000
|
||||
ReplaceMeterAction->>数据库: 2. 建新表:code=E-501-R1, is_active=true, replaced_meter_id=旧表id, initial_reading=5000, multiplier=1
|
||||
ReplaceMeterAction->>数据库: 提交事务
|
||||
Filament-->>王主管: 跳转新表 ViewMeter
|
||||
```
|
||||
|
||||
## 旧表 / 新表数据对照
|
||||
|
||||
| 字段 | 旧表 E-501 | **新表 E-501-R1** |
|
||||
|---|---|---|
|
||||
| `code` | E-501 | **E-501-R1** |
|
||||
| `is_active` | **false** | true |
|
||||
| `installed_at` | 2018-XX-XX(原值) | 2026-05-26 |
|
||||
| `decommissioned_at` | **2026-05-26** | null |
|
||||
| `decommission_reason` | **Replaced** | null |
|
||||
| `final_reading` | **5000** | null |
|
||||
| `initial_reading` | (历史值不动)| **5000**(继承)|
|
||||
| `multiplier` | 1 | 1(继承) |
|
||||
| `replaced_meter_id` | null | **旧表 id** |
|
||||
| `community_id`, `asset_id`, `fee_type_id` | 不动 | 继承 |
|
||||
|
||||
## 5 月份的抄表 + 账单
|
||||
|
||||
换表那个月的账单:
|
||||
|
||||
```
|
||||
本月用量 = current(新表第一次抄)+ initial(=5000) - previous(=5000)
|
||||
= (50 + 5000) - 5000
|
||||
= 50 度
|
||||
```
|
||||
|
||||
新表 5 月底第一次抄读到 50(物理表头),系统存 `current_reading = 50 + 5000 = 5050`,`previous_reading = 5000`(继承),`consumption = 50`。账单按 50 度算,业户感觉不到换表。
|
||||
|
||||
> [!info] 抄表员录入逻辑
|
||||
> 抄表员现场看到新表是 50,**系统应自动加上 5000 存为 5050**(避免抄表员手动算)。或者抄表员录 50,系统在保存时自动加 5000。具体实现看 `MeterReadingsRelationManager` 的 form。
|
||||
|
||||
## 业户视角
|
||||
|
||||
业户**几乎感受不到** —— 只看到下月账单仍是正常用量。
|
||||
|
||||
唯一感知:换表当天可能短暂断电断水(物理操作)。物业应**提前通知**业户。
|
||||
|
||||
## 整链追溯
|
||||
|
||||
如果以后这张 E-501-R1 又出问题再换 → 新表 E-501-R2,`replaced_meter_id` 指 R1。如此累加:
|
||||
|
||||
```
|
||||
E-501 (原生) → E-501-R1 (第 1 次换) → E-501-R2 (第 2 次换) → E-501-R3 ...
|
||||
```
|
||||
|
||||
详见 [[replacement-chain]]"整条链的追溯"段。
|
||||
|
||||
## 常见问题
|
||||
|
||||
> [!question] 旧表 `final_reading` 填错了能改吗?
|
||||
> 旧表的 `final_reading` 严格上属于"已退役表的字段",`MeterPolicy::update()` 在 `is_active=false` 时拒绝改([[decommission-and-locking]] 守护)。
|
||||
>
|
||||
> 改错的话:
|
||||
> - 通过 tinker 修(运维操作,留备注)
|
||||
> - 或者把 `decommissioned_at = null` 让表"复活"(Policy 可能不允许),再走完整换表流程
|
||||
>
|
||||
> **预防**:换表 Modal 提交前与抄表员书面确认 final_reading。
|
||||
|
||||
> [!question] 新表 multiplier 与旧表不同可以吗?
|
||||
> 可以(form 上可改),但**强烈不推荐**。理由见 [[replacement-chain]]"常见问题"段:不同 multiplier 让用量计算公式变,业户对账困难。
|
||||
|
||||
> [!question] 新表编号 -R1 不喜欢能改成别的吗?
|
||||
> Modal 表单允许改 `code`,但**强烈不推荐**:
|
||||
> - `-R1` 是标准化命名,审计 / 报表 / 后续换表的 `-R2` 都基于这个 pattern
|
||||
> - 改成自定义 code(如 "E-501-NEW")会破坏 `nextReplacementCode()` 算法,下次换表生成 `E-501-NEW-R1` 看着别扭
|
||||
|
||||
> [!question] 换表后业户对历史账单有异议怎么办?
|
||||
> 历史 reading 都关联到旧表(`meter_id=旧表 id`),不会因换表丢失。审计可:
|
||||
>
|
||||
> - 后台找旧表 → 看历次 reading(只读)
|
||||
> - 拿物理表照片(若有)
|
||||
> - 拿换表前的累计读数(旧表 final_reading)对照
|
||||
|
||||
> [!question] 业户搬走永久弃用表,这种"换表"怎么处理?
|
||||
> 那不是换表,是 [[decommission-without-replacement|退役不换表]]。`decommission_reason=Removed` 或 `Expired`,不建新表。
|
||||
|
||||
> [!question] 旧表是 active 但有未结账 reading,能换表吗?
|
||||
> 系统**不阻止**(Action 不查未结账 reading)。但业务上:
|
||||
>
|
||||
> - 应先生成未结账 reading 的 Bill(走 [[bill-generation-pipeline]])
|
||||
> - 否则换表后那些 reading 永远不会被处理(它们关联旧表)
|
||||
>
|
||||
> 推荐流程:**换表前先把旧表当月抄表录入 + 生成 Bill** → 然后再换表。
|
||||
|
||||
## 异常分支
|
||||
|
||||
- 不换表只退役 → [[decommission-without-replacement]]
|
||||
- 误换表想撤销 → 困难,见 [[replacement-chain]]"常见问题"段
|
||||
- 单纯换 multiplier 不换表 → 不推荐(应换表保留历史)
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [[meter-vs-meter-reading]]
|
||||
- [[replacement-chain]]
|
||||
- [[decommission-and-locking]]
|
||||
- [[decommission-without-replacement]]
|
||||
- [[register-single-meter]]
|
||||
Reference in New Issue
Block a user