186 lines
8.1 KiB
Markdown
186 lines
8.1 KiB
Markdown
---
|
||
title: prop-acc · meter · 场景 - 新社区批量建表 + 初始读数 Excel 导入
|
||
aliases:
|
||
- 批量建表
|
||
- 新社区计量表初始化
|
||
- init-new-community-batch
|
||
- 场景-新社区批量建表
|
||
tags:
|
||
- 场景
|
||
- prop-acc
|
||
- 计量表
|
||
- 表管理
|
||
- 批量导入
|
||
audience:
|
||
- 业务人员
|
||
- 抄表员
|
||
status: 已发布
|
||
sub_feature: meter
|
||
last_review: 2026-05-26
|
||
code_version: 2026-05-22
|
||
---
|
||
|
||
# 场景:新社区批量建表 + 初始读数 Excel 导入
|
||
|
||
物业**新接管社区**(或老社区从 0 接入本系统),需要**批量建表 + 录初始读数**。通过 `MeterInitializationImporter` + `ImportActionWithExcel` 一次性导入。
|
||
|
||
## 典型情境
|
||
|
||
> [!example] 真实情境
|
||
> 平台新签了"嘉禾花园"社区,本月底接管。该社区有 300 户业主 + 公共部位 + 商铺,合计约 1,200 张表(每户水电气 3 张 + 公共部位 + 商铺各类)。
|
||
>
|
||
> 物业财务王主管不可能手工建 1,200 张表,**走批量导入**:
|
||
>
|
||
> 1. 抄表员李师傅 + 物业前任团队 出 Excel 表(包含每张表的房号、表号、初始读数)
|
||
> 2. 王主管在系统下载"建表初始化模板"
|
||
> 3. 把数据填入模板 → 上传 → 系统批量建表
|
||
|
||
## 业务人员视角
|
||
|
||
### 第 1 步:下载初始化模板
|
||
|
||
后台 → 计量表 → 列表 → 顶部 **"下载初始化模板"** 按钮(`ExportMeterInitializationTemplateAction`)。
|
||
|
||
下载到的 Excel 包含:
|
||
|
||
| 列 | 说明 | 示例 |
|
||
|---|---|---|
|
||
| 房号 / 资产编号 | 关联 asset(必填,系统按房号查 asset_id) | 12-3-501 |
|
||
| 费用类型 | 水费 / 电费 / 燃气费(必填) | 电费 |
|
||
| 表编号 | 物理表牌号(必填) | E-501 |
|
||
| 倍率 | multiplier(可选,默认 1)| 1 |
|
||
| 初始读数 | initial_reading(必填,首次接管时表上的读数)| 0 / 8523 / etc. |
|
||
| 安装日期 | installed_at(可选,默认导入日)| 2026-05-26 |
|
||
| 备注 | (可选) | "新装" |
|
||
|
||
模板列名清晰,业务人员 / 抄表员看得懂。
|
||
|
||
> [!warning] 模板列含义"双义"问题(已知 issue)
|
||
> 当前 `MeterInitializationImporter` 用**一个 Importer 处理两种 Excel layout**(住宅单元 vs 商铺/公共)。某些列 label 是"双义"形式,导入选项里选错 `asset_type` 不报错,只是数据写到错误字段(silent corruption)。issue.md Q5 已记录,待拆成两个独立 Importer。**当前预防**:务必仔细选 asset_type。
|
||
|
||
### 第 2 步:填写数据
|
||
|
||
物业 / 抄表员把 1,200 张表的信息填入模板。
|
||
|
||
关键字段对齐:
|
||
|
||
- 房号:对应系统里 asset 表已存在的编号(若不存在,先到 community 模块建 asset)
|
||
- 费用类型:对应系统配置的 FeeType(水/电/燃气,各社区独立配置)
|
||
- 表编号:物业自编(常见 `<费用类型简写>-<房号>` 模式)
|
||
- 初始读数:**接管当天**的物理表读数(关键!首次接管之前的用量物业不管)
|
||
|
||
### 第 3 步:上传 + 导入
|
||
|
||
后台 → 计量表 → 列表 → 顶部 **"导入初始化"** 按钮(`ImportActionWithExcel` + `MeterInitializationImporter`)→ 选 asset_type(住宅 / 商铺)→ 上传 Excel → 提交。
|
||
|
||
系统:
|
||
|
||
1. **解析 Excel**(走 `BaseImporter` + `ImportActionWithExcel`,支持 .xlsx / .xls / .csv)
|
||
2. **每行校验**(房号 asset 存在?费用类型存在?表编号是否在该社区重复?)
|
||
3. **批量建 Meter**(每行一张 Meter 记录)
|
||
4. **可选:同时建第一条 MeterReading**(若模板含"初始读数",建初始 reading 来锁定 `previous_reading` 起点)
|
||
5. **报告**:成功 N 张,失败 M 张 + 每条失败的原因
|
||
|
||
> [!info] BaseImporter + chunk rollback
|
||
> 走 `App\Filament\Importers\BaseImporter`(host 基类,详见 saas-baseline 规范)+ `TransactionalImportCsv` job。一批 100 行任意一行失败 → 该批全回滚。
|
||
>
|
||
> 这避免"部分建好部分没建"的脏中间态。失败的批可下载"失败行" Excel,修复后再导入。
|
||
|
||
### 第 4 步:核对
|
||
|
||
导入后:
|
||
|
||
- 后台 → 计量表 → 按社区过滤 → 看是否 1,200 张表都在
|
||
- 抽样核对:打开几张表看初始读数对不对
|
||
|
||
### 第 5 步:启动月度抄表
|
||
|
||
接管下一个月 → 抄表员去现场抄读数(走 [[read-batch-via-excel-import]] 或 [[read-single-meter-manual]])→ 系统按 `current - initial × multiplier` 算用量 → 生成第一份账单(走 [[bill-generation-pipeline]])。
|
||
|
||
## 系统流程
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant 王主管
|
||
participant Filament
|
||
participant ImportActionWithExcel
|
||
participant MeterInitializationImporter
|
||
participant 数据库
|
||
|
||
Note over 王主管: 已填好 1200 行 Excel
|
||
|
||
王主管->>Filament: ListMeters → 导入初始化 → 选 asset_type + 上传
|
||
Filament->>ImportActionWithExcel: parse .xlsx
|
||
ImportActionWithExcel->>MeterInitializationImporter: 按 chunk 处理(100 行/批)
|
||
|
||
loop 每批
|
||
MeterInitializationImporter->>数据库: 开启事务
|
||
loop 每行
|
||
MeterInitializationImporter->>数据库: 校验 asset / fee_type / code 唯一
|
||
alt 校验通过
|
||
MeterInitializationImporter->>数据库: 建 Meter + 可选 initial MeterReading
|
||
else 校验失败
|
||
MeterInitializationImporter->>MeterInitializationImporter: 收集失败行
|
||
end
|
||
end
|
||
alt 全成功
|
||
MeterInitializationImporter->>数据库: 提交
|
||
else 任一失败
|
||
MeterInitializationImporter->>数据库: 回滚整批
|
||
end
|
||
end
|
||
|
||
MeterInitializationImporter-->>Filament: 报告 "成功 1198,失败 2"
|
||
Filament-->>王主管: 通知 + 下载失败行 Excel
|
||
```
|
||
|
||
## 业户视角
|
||
|
||
业户**不感知**这一步。新接管社区会发个公告"本月起本物业系统升级,各位业户的水电气计量将从 X 月 X 日起按本系统记账"。具体业户看到的:
|
||
|
||
- 接管前最后一份账单(由前任物业 / 自建系统出)
|
||
- 接管后第一份账单(由本系统出,用量从接管那天起算)
|
||
|
||
中间**绝不能有"重复账单"或"漏账"** —— 接管时的 `initial_reading` 必须准确反映物理表当时读数。
|
||
|
||
## 常见问题
|
||
|
||
> [!question] 为什么需要"初始读数"?
|
||
> 系统计算用量公式是 `(current - previous) × multiplier`。新表的"上一次读数"在系统里没有,所以接管时存的 `initial_reading` 就是"`previous_reading` 的起点"。后续每月抄表 → 当前 - 上次 = 用量。
|
||
>
|
||
> 如果不填初始读数 → 第一次抄表算用量会爆炸(`current - 0 = 所有历史用量`),业户被收一笔巨账,投诉。
|
||
|
||
> [!question] 导入失败的常见原因?
|
||
> - **房号(asset)不存在**:在 community 模块的 asset 还没建好。先建 asset 再导入表
|
||
> - **费用类型不存在**:RatePlan 没配置。先到 FeeType 配置
|
||
> - **表编号在该社区重复**(社区内 code 应唯一,虽然 issue.md Q5 提到目前是 nullable + 非 unique 的"待治理"状态)
|
||
> - **倍率格式错**(非数字 / 负数)
|
||
> - **初始读数格式错**(非数字 / 负数)
|
||
|
||
> [!question] 失败的行可以单独处理吗?
|
||
> 可以。导入完成后系统提供"下载失败行"Excel(走 host 的 `TransactionalImportCsv` 机制),业务人员修复后单独导入失败行。已成功的不影响。
|
||
|
||
> [!question] 同一社区多次导入会重复建表吗?
|
||
> 视 Importer 实现。若有 unique 校验(asset_id + fee_type_id 不可重复)→ 重复行会失败,需手工合并。若无校验 → 重复建,**灾难**。
|
||
|
||
> [!question] 老社区已经有一年的抄表历史,接管时怎么办?
|
||
> 简化做法:**只导入接管那天的状态**(initial_reading = 接管那天的物理读数),历史数据**不进系统**(在 Excel 备查)。
|
||
>
|
||
> 复杂做法:**导入历史 reading 数据**,让本系统有完整历史。需要业务方决定(用户对账复杂度 vs 系统数据完整度的权衡)。
|
||
|
||
> [!question] 商铺表 / 公共部位表怎么导入?
|
||
> 同样走 `MeterInitializationImporter`,但**选不同 asset_type**(public / shop)。导入时系统按 asset_type 决定列含义。详见 issue.md Q5"双义列名"问题。
|
||
|
||
## 异常分支
|
||
|
||
- 单张新表(后续装机 / 个别加表)→ [[register-single-meter]]
|
||
- 老表换新表 → [[replace-broken-meter]]
|
||
- 抄表(初始化后日常)→ [[read-batch-via-excel-import]] / [[read-single-meter-manual]]
|
||
|
||
## 相关文档
|
||
|
||
- [[meter-vs-meter-reading]]
|
||
- [[register-single-meter]]
|
||
- [[read-batch-via-excel-import]]
|
||
- [[bill-generation-pipeline]]
|