P3+P4+P5: prop-acc 迁移到多域 UDAS,新建 4 域骨架与顶层入口

P3 — prop-acc 30 文件迁移到多域 UDAS 结构:
- 3 概念:旧 prop-acc/一次性收费/概念-*.md
         → prop-acc/concepts/adhoc-*.md (kebab-case 英文)
- 25 场景:旧 prop-acc/一次性收费/场景-*.md
         → prop-acc/scenarios/adhoc-*.md
- 子文件夹 index.md → prop-acc/maps/knowledge-map.md (域内地图)
- prop-acc/index.md 重写为域首页(embed knowledge-map)
- 删除空目录 prop-acc/一次性收费/

每个迁移文件:
- title 加域前缀 "prop-acc · "
- aliases 含原 title (带空格) + 原文件名 basename (无空格),保证既有 [[...]] 引用解析
- status: stable → 已发布 / draft → 草稿 (UDAS 中文枚举)
- last_reviewed → last_review (UDAS 字段名)
- tags 补加 UDAS 类型分类 "概念" / "场景"
- 路径式 WikiLink 清除:
  * [[../预存款/index|XX]] → [[预存款]]
  * [[一次性收费/index|XX]] → [[prop-acc · 一次性收费索引]]

P4 — 4 个新业务域骨架:
- community (社区管理)
- administrative (行政人事)
- patrol (巡护工单)
- resident-portal (业户门户)
每域含 index.md (域首页) + maps/knowledge-map.md (域内地图模板)。
另补 cross/index.md + cross/maps/cross-domain-map.md。

P5 — 顶层入口:
- index.md: 站点首页 (Quartz 着陆点),embed domain-map
- maps/domain-map.md: 5 业务域 + cross 的索引表

迁移后状态:
- 共 50 篇 .md (30 原 + 8 跨域 stub + 4 域 index + 4 域 map + 2 cross + 2 root)
- 残留路径式 WikiLink: 0
- 残留英文 status: 0
- 残留 last_reviewed 字段: 0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Willie
2026-05-25 20:44:43 +08:00
parent 0032f32b7a
commit b7c0cd6e0c
40 changed files with 684 additions and 118 deletions

View File

@@ -0,0 +1,207 @@
---
title: prop-acc · 场景 - 审计 - IC 卡库存与售出数对账
aliases:
- 场景 - 审计 - IC 卡库存与售出数对账
- 场景-审计-IC卡库存与售出数对账
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 审计对账
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:IC 卡库存与售出数对账
物业月底核对:**系统记录卖出的 IC 卡数量** 是否等于 **库存盒里减少的物理 IC 卡数量**
> [!warning] 系统不直接管物理库存
> 本系统**只管财务**(收了多少钱),**不管实物**(IC 卡盒里还剩几张)。物理库存盘点是物业**独立的内部流程**,本场景描述如何用系统数据**辅助核对**物理库存。
## 典型情境
> [!example] 真实情境
> 5 月 31 日,物业财务王姐做月度库存盘点。
>
> - 月初库存:100 张工本卡(已制好的空白 IC 卡)
> - 月底盘点:剩 47 张
> - 推断:**这个月用掉 53 张**
>
> 在 Filament 后台查"5 月 IC 卡售出数",**应该等于 53 张**。如果不等,需要排查。
## 业务人员视角
### 步骤 1:盘点物理库存
```
1. 月初库存(从上月结存) 100 张
2. 本月入库(新采购) +50 张
3. 本月理论可用 150 张
4. 月底盘点(数库存盒) -47 张
─────────────────────────────────────
5. 本月实际"消耗" 103 张
```
### 步骤 2:从系统拉售出数据
```sql
SELECT
COUNT(*) AS ,
SUM(quantity) AS
FROM acc_ad_hoc_events ahe
JOIN acc_rate_plans rp ON ahe.rate_plan_id = rp.id
WHERE rp.name LIKE '%IC 卡%'
AND ahe.occurred_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59'
AND ahe.status = 'completed';
```
输出例:
```
售出订单数:90 单
卡总张数:103 张 (有些订单买多张)
```
### 步骤 3:对账
```
物理消耗 vs 系统售出
103 vs 103 ✅ 完美一致
```
或者:
```
物理消耗 vs 系统售出
103 vs 101 ❌ 差 2 张
→ 物理少了 2 张 / 系统多算 2 张
```
### 步骤 4:差额排查
#### 差额 > 0(物理消耗 > 系统售出)
**意味着**:卡发了但没记账。可能原因:
| 原因 | 处理 |
|---|---|
| 给 VIP 业户**免费**发卡(没收钱也没记录)| 物业政策合规,要补登记 0 元订单 |
| 测试卡(写卡测试用了几张)| 算损耗 |
| 业务人员私发 | **严重**,核查员工 |
| 卡丢失 / 制卡失败报废 | 算损耗 |
#### 差额 < 0(物理消耗 < 系统售出)
**意味着**:记账了但卡没发。可能原因:
| 原因 | 处理 |
|---|---|
| 业户已付款但实物没拿(走 [[场景-异常-支付完成但实物发不出]])| 检查"待补发清单",物业还在保管 |
| 录单时数量填错(多录了)| 检查录入异常订单,可能要 [[场景-取消-录错金额作废重做]] |
| 业户付了款作废后忘了取回卡 | 物业归档 |
## 物理库存管理建议
> [!tip] 建议物业建一份独立的库存台账
> 不在系统里(系统不管物理库存),但用 Excel / 纸质本子记:
```
=== IC 卡库存台账 ===
日期 操作 数量 余额 经办人 备注
2026-04-30 月初余结存 100 上月结存
2026-05-03 采购入库 +50 150 李四 合同 #2026005
2026-05-15 发给业户 -1 149 张三 房号 12-3-501
2026-05-15 发给业户 -2 147 张三 房号 8-2-301
...(每天明细)
2026-05-31 月底盘点 47 王姐 实物数对
```
每周/每月与系统数据对照。
## 系统流程
```mermaid
sequenceDiagram
participant 财务
participant 物理库存
participant Filament/DB
participant 业务人员
Note over 财务: 月底
财务->>物理库存: 数库存盒
物理库存-->>财务: 47 张
财务->>财务: 计算消耗 = 100 + 50 - 47 = 103
财务->>Filament/DB: 查 5 月 IC 卡售出数
Filament/DB-->>财务: 103 张
财务->>财务: 对账 ✅
Note over 财务: 若不一致
财务->>业务人员: 找差额
业务人员-->>财务: 解释(免费发卡 / 录入错误 / 报废等)
```
## 其他实物的对账方法
同样的方法可以对账:
| 实物 | 系统侧查询 |
|---|---|
| **装修出入证** | `SUM(quantity) WHERE rate_plan.name LIKE '%装修出入证%'` |
| **泳票(纸质)** | `SUM(quantity) WHERE rate_plan.name LIKE '%泳票%'` |
| **充值码 / 充值卡** | `COUNT(*) WHERE rate_plan.name LIKE '%充值%'` |
## 常见问题
> [!question] 为什么系统不直接管物理库存?
> 物理库存涉及**采购 / 入库 / 报废 / 盘点** 等独立流程,可能跨多个仓库 / 多种实物。**绑到收费系统里会让收费系统过重**。最佳实践:
> - 库存独立做(Excel / 专门的 ERP)
> - 收费系统专注于"卖出与收钱"
> - 月底用对账连接两者
> [!question] VIP 业户免费发卡,系统里要建 0 元订单吗?
> **强烈建议建**。便于库存对账。Filament 后台支持金额 = 0(不会失败)。备注栏注明"VIP 免费 + 审批单号"。
> [!question] 制卡过程中报废的卡怎么入账?
> 系统侧**不录任何订单**(没有交易发生)。在库存台账里**算损耗**:
> ```
> 日期 制卡失败报废 -1 余额 X 备注 测试新读卡器
> ```
> [!question] 差额超过 10 张能不能不查?
> **强烈不建议**。差额是**审计预警信号**,长期不查可能掩盖:
> - 员工私发
> - 财务挪用
> - 系统漏录
>
> 建议:**月度差额 > 5 张必须给出书面解释**。
## 与"现金对账"的区别
| 对账类型 | 对账对象 | 数据源 | 频率 |
|---|---|---|---|
| [[场景-审计-月底现金对账\|现金对账]] | 系统订单 vs 收银抽屉 | 数据库 + 物理现金 | 每月 |
| **库存对账(本场景)** | 系统订单 vs 物理库存盒 | 数据库 + 物理盘点 | 每月 |
| 作废抽查 | 作废订单的事由记录 | 数据库 meta 字段 | 每季 |
三种对账**独立做但互相印证** —— 现金对账过了但库存不对,可能是 VIP 免费发卡;反之可能是手工卖了卡没录系统。
## 相关概念
- [[场景-A流-前台购买IC卡]] — 售出的数据来源
- [[场景-审计-月底现金对账]] — 财务对账
- [[场景-审计-作废事由抽查]] — 第三种对账
## 异常分支
- 物理少了 → 内部排查
- 系统少了 → 找漏录单 / 补登记
- 多个月持续不一致 → **必查清** 不能拖

View File

@@ -0,0 +1,257 @@
---
title: prop-acc · 场景 - 审计 - 月底现金对账
aliases:
- 场景 - 审计 - 月底现金对账
- 场景-审计-月底现金对账
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 审计对账
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:月底现金对账
财务每月月底**核对前台收的现金**与**系统记录**是否一致。也叫"日结" / "月结"。
> [!info] 给谁看
> 主要给**财务人员**。业户不需要懂这部分。
## 典型情境
> [!example] 真实情境
> 5 月 31 日,物业财务王姐准备月度结账。她要核对一次性收费 5 月份**前台收的现金总额**是否等于**收银抽屉的实际现金**。
## 核心问题:三个数要对得上
```mermaid
graph LR
A[A 系统记录<br/>CollectionOrder 表] --> D{对账}
B[B 收据汇总<br/>Receipt 表] --> D
C[C 物理现金<br/>抽屉点数] --> D
D --> E[✅ 三方一致]
D --> F[❌ 不一致 → 追查]
classDef record fill:#dbeafe
classDef physical fill:#fef3c7
classDef result fill:#dcfce7
classDef fail fill:#fee2e2
class A,B record
class C physical
class E result
class F fail
```
如果三者一致,**通过**。如果不一致,需要逐笔排查。
## 业务人员视角(财务)
### 步骤 1:拉系统数据
在 Filament 后台:
```
路径 1:CollectionOrders 列表
├── 筛选:collection_completed_at 在 2026-05-01 ~ 2026-05-31
├── 筛选:collection_type = AdHoc
├── 筛选:payment_method = "现金"
└── 求和:actual_amount
得到 → A 系统记录(现金部分)
```
或直接走 SQL:
```sql
SELECT
COUNT(*) AS ,
SUM(actual_amount) AS
FROM acc_collection_orders
WHERE collection_completed_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59'
AND collection_type = 'ad_hoc'
AND payment_method LIKE '%现金%'
AND status = 'completed';
```
### 步骤 2:对照 Receipt 表(验证内部一致)
```sql
SELECT
COUNT(r.id) AS ,
SUM(r.amount) AS
FROM acc_receipts r
JOIN acc_collection_orders co ON r.collection_order_id = co.id
WHERE co.collection_completed_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59'
AND co.collection_type = 'ad_hoc'
AND co.payment_method LIKE '%现金%'
AND r.status = 'issued';
```
**A 和 B 应该完全相等**(因为每笔订单生成一张收据,金额完全对应)。如果不等 → 数据库不一致问题,**严重**,要技术介入。
### 步骤 3:点物理现金
财务到前台:
1. 打开收银抽屉
2. 数所有钞票 + 硬币
3. 减掉初始备用金(通常 ¥500-1000)
4. 得到 C 现金部分
### 步骤 4:对照 A vs C
| 情况 | 含义 | 处理 |
|---|---|---|
| **A = C** | ✅ 完美对账 | 月底归档,提现到银行 |
| **A > C**(系统多)| 现金少了 | 找差额:可能丢失 / 找零错 / 员工挪用 |
| **A < C**(现金多)| 现金多了 | 找差额:可能少录单 / 找零少给 / 业户给多了没退 |
差额 ≥ ¥10 都要逐笔排查。
### 步骤 5:逐笔排查(差额情况)
```
1. 列出所有现金订单清单(订单号 + 金额 + 时间 + 业户)
2. 对照前台手工日志(如果有)/ 监控录像
3. 找到可疑的几笔:
├── 录入时间晚了几小时(可能延后录入)
├── 金额特殊(整数 / 没零头)
└── 业户名字可疑
4. 联系业户 / 当事员工核实
```
## 多渠道场景
实际场景不只有现金。一次性收费可能有 5+ 种支付渠道:
| 渠道 | 对账依据 |
|---|---|
| 现金 | 收银抽屉点数 |
| 微信支付 | 微信商户后台流水 |
| 支付宝 | 支付宝商户后台流水 |
| POS 刷卡 | 银行账单 |
| 银行转账 | 对公账户流水 |
**每种渠道独立对账**:
```sql
SELECT
payment_method,
COUNT(*) AS ,
SUM(actual_amount) AS
FROM acc_collection_orders
WHERE collection_completed_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59'
AND collection_type = 'ad_hoc'
AND status = 'completed'
GROUP BY payment_method;
```
输出例:
```
现金 125 笔 ¥3,820
微信 42 笔 ¥1,260
支付宝 18 笔 ¥540
POS刷卡 8 笔 ¥280
─────────────────────────
合计 193 笔 ¥5,900
```
财务对照每个渠道的外部对账单。
## 系统流程
```mermaid
sequenceDiagram
participant 财务
participant Filament/DB
participant 前台
participant 微信商户
participant 支付宝商户
participant 银行
财务->>Filament/DB: 月度筛选 + 求和(按支付方式)
Filament/DB-->>财务: 各渠道金额
财务->>前台: 点物理现金
前台-->>财务: 抽屉总额
财务->>微信商户: 查流水
微信商户-->>财务: 微信总收款
财务->>支付宝商户: 查流水
支付宝商户-->>财务: 支付宝总收款
财务->>银行: 查对公账单
银行-->>财务: 转账 + POS 流水
财务->>财务: 逐渠道对账
财务->>财务: 不一致逐笔排查
```
## 常见问题
> [!question] 系统多了 ¥30,可能是什么原因?
> - 业户付完拿走货,职员忘了给找零(¥50 收 ¥20 商品,找零给少了)
> - 当天工作交接,前班的现金没全部移交
> - 销售退款没退,系统已记作废但前台没退现金给业户
> [!question] 系统少了 ¥50,可能是什么原因?
> - 漏录单(收了钱忘录系统)
> - 找零给多了
> - 业务人员临时挪用(严重,要核查)
> [!question] 每次差几块钱(< ¥10)能忽略吗?
> **不建议**。差小钱不一定是 bug,但**长期累积** + **不追究** = 内部审计黑洞。建议:
> - 差 < ¥10 也记录追查
> - 差 ≥ ¥100 当周必查清
> [!question] 业务人员能修改历史订单的支付方式吗?
> **不能**(订单 Completed 后不可编辑)。如果发现某笔订单的 payment_method 录错(比如填了"现金"实际是"微信"),走 [[场景-已收款作废]] + 重新录入。
> [!question] 月底前的几小时高峰怎么处理?
> 5 月 31 日 23:59 录入的订单 vs 6 月 1 日 00:01 录入,在 SQL 里**严格按时间戳归属**。建议月底前后 30 分钟**减少操作**,避免跨月归类争议。
## 月度报表的标准格式(建议)
```
=== 一次性收费 2026 年 5 月对账报告 ===
【系统数据】
现金: ¥3,820 (125 笔)
微信: ¥1,260 (42 笔)
支付宝: ¥540 (18 笔)
POS刷卡: ¥280 (8 笔)
─────────────────────
合计: ¥5,900 (193 笔)
【外部数据】
收银抽屉点数: ¥3,820 ✅
微信商户后台: ¥1,260 ✅
支付宝商户后台: ¥540 ✅
银行 POS 入账: ¥280 ✅
【差额追查】
【作废订单(对照)】
本月作废: 3 笔 ¥150
其中 Pending 作废: 2 笔(超时/撤单)
其中 Completed 作废: 1 笔(已退款 ¥30,银行原路)
【签字】
财务:______ 物业经理:______ 日期:______
```
## 相关概念
- [[概念-CollectionOrder与Receipt]] — 三件套数据是对账的核心
- [[场景-A流-前台购买IC卡]] — 现金交易的入口
- [[场景-B流-小程序下单+微信支付]] — 微信渠道数据来源
- [[场景-B流-小程序下单+支付宝]] — 支付宝渠道数据来源
- [[场景-已收款作废]] — 作废订单对对账的影响

View File

@@ -0,0 +1,235 @@
---
title: prop-acc · 场景 - 审计 - 作废事由抽查
aliases:
- 场景 - 审计 - 作废事由抽查
- 场景-审计-作废事由抽查
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 审计对账
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:作废事由抽查
物业**财务 / 内审 / 上级** 定期抽查作废订单,验证**作废原因记录是否完整、合理**。防止业务人员**滥用作废功能**(挪用现金、做账漏洞)。
> [!info] 为什么这个对账很重要?
> 一次性收费的 [[场景-已收款作废\|已收款作废]] 涉及**资金退还**。如果业务人员说"作废了"但没真退,**或者作废用来掩盖之前的挪用**,系统层面看不出来 —— 必须靠**事由记录抽查**反向追查。
## 典型情境
> [!example] 真实情境
> 6 月份内审来检查 5 月份记录:
> - 5 月共有 8 笔已收款作废订单
> - 总作废金额 ¥1,520
>
> 内审要求**逐笔出示作废原因 + 资金处理凭证**。
## 业务人员视角(被抽查方)
### 内审会问什么
每笔作废订单,内审会问:
| 问题 | 你要拿出的证据 |
|---|---|
| 为什么作废? | meta.voided_reason 完整记录 |
| 谁审批的? | meta.voided_by 是 supervisor 级别员工 |
| 资金怎么处理的? | 现金退还签字 / 微信退款记录 / POS 撤销凭证 |
| 业户确认收到退款了吗? | 业户签字 / 微信沟通截图 |
| 是否后续重新下单? | 如果是,关联新订单号 |
### 准备资料
```
1. 拉出 5 月份所有作废订单
2. 按订单号逐一整理:
├── 截图 Filament 后台订单详情
├── 截图 meta.voided_* 字段(JSON 格式)
├── 附微信退款记录 / 现金签收单
└── 附业户沟通截图(如果有)
3. 装订成册交内审
```
## 查作废订单的 SQL
```sql
SELECT
ahe.id,
ahe.created_at AS ,
ahe.meta->>'voided_at' AS ,
ahe.meta->>'voided_reason' AS ,
ahe.meta->>'voided_by' AS ID,
u.name AS ,
ahe.amount AS ,
rp.name AS ,
cup.user_id AS ID
FROM acc_ad_hoc_events ahe
JOIN acc_rate_plans rp ON ahe.rate_plan_id = rp.id
LEFT JOIN community_community_user_profiles cup ON ahe.community_user_profile_id = cup.id
LEFT JOIN users u ON CAST(ahe.meta->>'voided_by' AS INTEGER) = u.id
WHERE ahe.status = 'voided'
AND CAST(ahe.meta->>'voided_at' AS TIMESTAMP) BETWEEN '2026-05-01' AND '2026-05-31 23:59:59'
ORDER BY ahe.meta->>'voided_at' DESC;
```
## 健康的作废 vs 可疑的作废
> [!success] 健康的作废(对账通过)
```
voided_reason: "录入金额错误 ¥400 应为 ¥40。已通过微信原路退款 ¥400,
业户已确认收到。重新下一笔正确订单 CO-XXX。
处理人:王XX(夜班柜员)"
voided_at: 2026-05-15 19:23:45
voided_by: 5 (王XX)
✅ 内审评价:
- 原因清晰
- 资金处理写明(微信原路退款)
- 业户确认
- 关联新订单(可追溯)
```
> [!failure] 可疑的作废(内审会盯)
```
voided_reason: "作废"
voided_at: 2026-05-20 17:55:30
voided_by: 5
❌ 内审评价:
- 原因仅一个字,无解释
- 没说资金处理
- 没说业户是否确认
- 没说后续是否重做
- **强烈建议核查:是否有挪用现金嫌疑**
```
## 抽查指标
业务人员的"作废率"是一个重要指标:
```
作废率 = 作废订单数 / 总订单数
健康水平:< 3%
警戒水平:3% ~ 5%
严重水平:> 5%(必须人工核查每笔)
```
某员工的作废率**显著高于团队均值** → 可能是工作能力差(经常录错)或可疑(挪用)。
### 按员工统计
```sql
SELECT
u.name AS ,
COUNT(*) FILTER (WHERE ahe.status = 'voided') AS ,
COUNT(*) FILTER (WHERE ahe.status = 'completed') AS ,
ROUND(100.0 * COUNT(*) FILTER (WHERE ahe.status = 'voided')
/ NULLIF(COUNT(*), 0), 2) AS
FROM acc_ad_hoc_events ahe
LEFT JOIN users u ON CAST(ahe.meta->>'voided_by' AS INTEGER) = u.id
WHERE ahe.occurred_at >= '2026-05-01'
GROUP BY u.id, u.name
ORDER BY DESC;
```
输出例:
```
员工 | 作废笔数 | 完成笔数 | 作废率
李XX | 1 | 320 | 0.31% ✅
张XX | 3 | 280 | 1.07% ✅
王XX | 12 | 95 | 12.63% ❌ 必查
```
## 系统流程
```mermaid
sequenceDiagram
participant 内审
participant 业务人员
participant Filament/DB
participant 业务流程
Note over 内审: 季度审计
内审->>Filament/DB: 拉作废订单 + meta
Filament/DB-->>内审: 8 笔 ¥1520
内审->>业务人员: 出示原因 + 资金凭证
业务人员->>业务人员: 整理资料(微信截图、签收单)
业务人员-->>内审: 交付
内审->>内审: 逐笔检查
alt 原因清晰 + 资金凭证完整
内审-->>业务人员: ✅ 通过
else 原因模糊 / 凭证不全
内审-->>业务人员: ❌ 要求补充说明
业务人员->>业务流程: 联系业户补凭证
业务人员-->>内审: 补充材料
end
Note over 内审: 整理审计报告 → 上报集团
```
## 防止作废滥用的设计
> [!info] 系统设计上的几道防线
>
> 1. **作废必须填原因** —— Filament UI 强制必填 textarea
> 2. **记录 voided_by** —— 留谁的责任
> 3. **记录 voided_at** —— 留时间戳
> 4. **不能修改 voided_reason** —— 写入后只读
> 5. **作废后状态不可恢复** —— 不能事后"撤销作废"
>
> 这五道防线让作废操作**完全留痕**,事后审计有据可查。
## 常见问题
> [!question] 业务人员作废后能不能"修改作废原因"?
> **不能**。meta 字段写入后不可修改。如果原因写错了,需要技术介入(直接改数据库)且留**修改记录**。
> [!question] 内审能否要求**所有作废订单**逐笔检查?
> 可以。健康的物业**所有作废都应该有可解释的原因**。如果某月作废多了一倍以上,**全数检查**是必要的。
> [!question] 业户主动撤单(Pending 单)也要审吗?
> 不需要。Pending 单作废**没有资金涉及**(业户没付款),审计风险低。但 voided_reason 也应该清楚(便于业户体验问题排查)。
> [!question] 系统能不能自动报警"高作废率员工"?
> 当前**没有自动报警**。可以挂 TODO:
> - 定时 job(每日 / 每周)算每个员工作废率
> - 超阈值的发邮件 / 微信通知管理员
> - 等业务方明确反馈再做
> [!question] 已经处罚过的员工,历史作废记录还能看到吗?
> **能**。作废记录**永久保留**,即使员工离职、被开除,他名下的所有操作都在数据库里有据可查。
## 与其他对账的对照
| 对账类型 | 对账对象 | 重点 |
|---|---|---|
| [[场景-审计-月底现金对账\|现金对账]] | 系统订单 vs 物理现金 | 钱在不在 |
| [[场景-审计-IC卡库存与售出数对账\|库存对账]] | 系统订单 vs 物理库存 | 货在不在 |
| **作废事由抽查(本场景)** | 作废订单的 meta 字段 | **原因合不合理 + 责任清不清楚** |
三种对账**完整覆盖** "钱、货、人" 三个维度。健康物业每月都做。
## 相关概念
- [[概念-AdHocEvent状态机]] — Voided 状态的不可逆性
- [[场景-已收款作废]] — 作废操作的入口
- [[场景-取消-录错金额作废重做]] — 健康的作废示例
## 异常分支
- 内审发现重大问题 → 报集团 / 公安(挪用)
- 业务人员书写不规范 → 加强培训 + 重写 meta 模板

View File

@@ -0,0 +1,146 @@
---
title: prop-acc · 场景 - 超时未付自动作废
aliases:
- 场景 - 超时未付自动作废
- 场景-超时未付自动作废
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 取消退款
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:超时未付自动作废
业户在小程序下单后**没有及时付款**,系统在订单到期后**自动作废**。
> [!warning] 实现状态
> 后端 `VoidAdHocEventAction` 已就绪。**自动扫描 scheduled job 尚未实现**(预定与 payment-gateway webhook 同期上线)。本场景描述上线后体验。
## 典型情境
> [!example] 真实情境
> 周三下午,陈先生在小程序上下单一张游泳卡 ¥200。下单完接了个电话,把这事忘了。
>
> 30 分钟后他想起来,打开小程序"我的订单",订单已经变成 "已作废"。原因栏写着:**[订单超时作废] expires_at 已过**。
## 业户视角
### 您看到什么
下单后超时未付,小程序"我的订单"里:
```
游泳卡(月卡)
订单号:CO-20260525-XXX
金额:¥200
状态:❌ 已作废
作废原因:订单超时未付款
```
> [!info] 不影响后续
> 您可以**立即重新下一单**。新订单按当前价格冻结(如果项目涨价了,以新价为准)。
### 为什么要超时?
> [!tip] 业户视角:为什么超时设计?
> 假设您下单不付款占着这个金额很久,后台一直把项目库存(比如装修证只有 100 张)留给您 —— 不公平。**超时机制让资源可循环**。
## 业务人员视角
### 业务人员一般不需要管
> [!success] 完全自动化
> Scheduled job 每隔一段时间(比如每小时)扫描全表,自动处理超时单。**前台不用做任何事**。
### 业务人员能看到什么
每个超时作废的订单在 Filament 后台:
- 状态:`Voided`
- meta 字段记录:`voided_at` / `voided_reason: "[订单超时作废]"` / `voided_by: null`(系统自动,无操作员)
### 如果业户来问"我的订单怎么没了"
```
1. 在 Filament 后台搜业户姓名 / 订单号
2. 找到 Voided 记录
3. 告诉业户:"您的订单在 X 月 X 日下午 X 点超时作废了,原因是没在 30 分钟内完成支付。请重新下单。"
```
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 小程序
participant 系统
participant Scheduled Job
业户->>小程序: 下单游泳卡 ¥200
小程序->>系统: CreatePendingAdHocEventAction
系统->>系统: 建 AdHocEvent + CO,expires_at = now + 30min
系统-->>业户: 返订单号,等待支付
Note over 业户: 业户忘了付钱
Note over Scheduled Job: 每小时扫描一次
Scheduled Job->>系统: 查询 CO where status=pending AND expires_at < now()
系统-->>Scheduled Job: 返回所有超时 Pending 单
loop 对每个超时单
Scheduled Job->>系统: VoidAdHocEventAction
系统->>系统: 级联废 AdHocEvent + CO
系统->>系统: 写 meta.voided_reason = "[订单超时作废]"
end
业户->>小程序: 想起来要付钱
小程序->>系统: 查询订单
系统-->>小程序: 状态 Voided
小程序-->>业户: 显示"订单已作废,请重新下单"
```
## 几个常见超时周期(可配置)
| 项目类型 | 推荐超时 | 理由 |
|---|---|---|
| **泳票 / 充电桩** | 30 分钟 | 业户高频下完即付 |
| **IC 卡** | 2 小时 | 业户可能要查档案、对房号 |
| **装修证(单张)** | 1 天 | 装修公司可能要走内部审批 |
| **装修证(批量)** | 7 天 | 大公司付款流程长 |
> [!warning] 跨渠道补缴场景请用长 expires_at
> 跨渠道补缴([[场景-跨渠道补缴]])时,儿女线上下单、老人现场付款 —— 中间可能隔几天。**这种场景建议 expires_at 设 7 天**,避免老人到前台时单子已废。具体配置看每个 RatePlan 的设置。
## 常见问题
> [!question] 我的订单超时了能恢复吗?
> **不能**。超时作废是终态。直接重新下单。
> [!question] 重新下单价格会不会涨?
> **可能**。系统按下单**当时的价格冻结**;如果上次下单到现在物业调价了,新订单按新价。
> [!question] 我付款的瞬间订单刚好超时,会重复扣款吗?
> **不会**。系统在 `MarkAdHocEventPaidAction` 内部有事务保护:如果订单已被作废,支付回调会失败,微信会原路退回。
> [!question] 物业前台能"延长有效期"吗?
> 当前**不支持**。要延长只能业户自己重新下单。是否要支持手动延长是个业务决策,等业务方反馈再加。
## 系统配置(技术细节,业务人员可跳过)
- 扫描 job 在 `app/Console/Kernel.php` 注册,每小时跑一次
- 查询语句:`SELECT * FROM acc_collection_orders WHERE status='pending' AND expires_at < NOW()`
- 调用 `VoidAdHocEventAction::handle($event, '[订单超时作废] expires_at < now()')`
## 相关概念
- [[概念-AdHocEvent状态机]] — Pending → Voided 流转
- [[概念-CollectionOrder与Receipt]] — `expires_at` 字段挂在 CollectionOrder 上的设计原因
- [[场景-B流-小程序下单+微信支付]] — 业户下单的正向流程
- [[场景-跨渠道补缴]] — 长 expires_at 的典型用例

View File

@@ -0,0 +1,150 @@
---
title: prop-acc · 场景 - 取消 - 录错金额作废重做
aliases:
- 场景 - 取消 - 录错金额作废重做
- 场景-取消-录错金额作废重做
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 取消退款
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:录错金额作废重做
业务人员**手滑录错金额**(常见:多打/少打一个零、串到隔壁字段)的修正流程。
## 典型情境
> [!example] 真实情境
> 周末下午泳池前台高峰期,职员小赵给陈太太录入泳票订单:
> - **应该录**:¥40(2 张 × ¥20)
> - **实际录**:¥400(数量栏串到金额栏)
>
> 陈太太微信支付完跳出来,看到收据写 ¥400 当场愣住:"这怎么扣这么多?!"
## 业务人员视角
### 应急步骤(2 分钟内搞定)
```
1. 当场承认错误,安抚业户
"对不起阿姨,这是我录错了,我马上给您处理。"
2. 在 Filament 后台找到这笔订单
├── 状态 Completed
├── 金额 ¥400
└── 业户名:陈太太
3. 走 VoidAction(作废)
├── 必填作废原因:
│ "录入金额错误,实际应为¥40。
│ 已向业户致歉,通过微信原路退款 ¥400。
│ 重新建一笔正确订单。"
├── 提交
└── 系统瞬间:订单 → Voided, 收据 → Voided
4. 微信商户后台发起退款 ¥400(原路退回业户)
5. 重新录入正确订单
├── 数量:2
├── 金额:¥40
├── 支付方式:现金(因为业户当面拿现金给你)
├── 备注:"对上一笔订单 CO-XXX 作废后重做"
└── 提交
6. 给业户出新收据
```
### 关键细节
> [!warning] 关键:**作废 + 重做必须连贯**
> 中间不要去做别的事,容易忘记重做。**一气呵成最稳妥**。
> [!tip] 重做时的支付方式怎么填?
> - 业户原本微信付的 ¥400 已经在退款中(需要几小时到账)
> - **重新付 ¥40 走现金最简单**(业户钱包随便拿)
> - 也可以让业户重新微信支付 ¥40(完全一笔新交易)
> - **不建议**:让业户等微信退款到账后再交 —— 业户体验差
## 与"已收款作废"的区别
| 维度 | 已收款作废([[场景-已收款作废]]) | 录错重做(本场景)|
|---|---|---|
| 触发场景 | 业户反悔、缺货、退货 | 业务人员录入失误 |
| 是否重做 | **不重做**(纯取消)| **必须重做**(业户确实要这个商品)|
| 复杂度 | 1 步:作废 | 2 步:作废 + 重做 |
| 资金 | 全额退给业户 | **退原金额** + **重收正确金额** |
| 业户体验 | 一切照常,只是没了 | 短暂困惑,但快速纠正 |
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 业务人员
participant 系统
participant 微信商户
业户->>业务人员: 出示错单 ¥400
业务人员->>系统: 找到 Completed 订单
业务人员->>系统: VoidAction (reason="录入金额错误...")
系统->>系统: AdHocEvent → Voided
系统->>系统: CollectionOrder → Failed
系统->>系统: Receipt → Voided
系统-->>业务人员: 作废成功
业务人员->>微信商户: 后台发起退款 ¥400
微信商户-->>业户: 几小时内到账
Note over 业户,业务人员: 同时,重新录入正确订单
业户->>业务人员: 拿出现金 ¥40
业务人员->>系统: 新建 AdHocEvent (¥40, 现金)
系统->>系统: 一气呵成三件套
系统-->>业务人员: 完成
业务人员->>业户: 新收据 + 实物
```
## 常见问题
> [!question] 重做的订单要不要在备注里写"对应原作废订单"?
> **强烈建议**。写"对上一笔订单 CO-XXX 作废后重做"。这样:
> - 财务对账时能看出"这两笔金额是同一笔业务"
> - 半年后审计抽查,能反查到完整事件
> [!question] 业户离开物业前没发现错单,事后才发现怎么办?
> 一样走作废 + 退款,但**沟通成本高**:
> - 联系业户:"系统发现一笔订单可能有误..."
> - 业户确认是否要重做
> - 退款走微信(原路)
> - 重做订单如果要新付款,**线上付款最方便**(让业户在小程序重新下单 + 支付)
> [!question] 业务人员自己发现录错 vs 业户发现录错,处理方式有区别吗?
> 没区别。但**业务人员自己发现要立刻处理**,不要等业户来质疑。
> [!question] 高峰期录单忙容易错,有什么预防方法?
> 1. **金额自动填**:在 Filament 后台,选 RatePlan 后金额自动算出 = `unit_price × quantity`,不要手改
> 2. **复核机制**:提交前 Modal 弹"确认 ¥XXX?" 让业务人员肉眼复核
> 3. **拆分付款步骤**:先收钱 + 数现金,再录入(确保实收金额对得上)
## 系统设计上的预防
> [!info] Filament Modal 已有的保护
> 当前 `CreateAdHocEvent` 表单:
> - 选 RatePlan 后**单价 + 总金额自动填**(避免手输错)
> - 提交前 Modal 显示金额(让业务人员肉眼复核)
> - 提交后给 success toast 通知(业务人员能即时看到结果)
>
> 如果还是错了 —— 通常是高峰期注意力分散,需要业务培训提醒。
## 相关概念
- [[概念-AdHocEvent状态机]] — Completed → Voided
- [[场景-已收款作废]] — 基础作废流程
- [[场景-A流-前台购买IC卡]] — 录入的正向流程

View File

@@ -0,0 +1,171 @@
---
title: prop-acc · 场景 - 取消 - 业户改主意主动撤单
aliases:
- 场景 - 取消 - 业户改主意主动撤单
- 场景-取消-业户改主意主动撤单
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 取消退款
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:业户改主意主动撤单
**B 流场景**:业户在小程序下完单但还没付款,自己主动取消。
> [!info] 与超时作废的区别
> [[场景-超时未付自动作废|超时作废]]是系统**被动**作废(到期了机器自动废)。本场景是**业户主动**操作。两者都只针对 Pending 状态,**已支付订单走 [[场景-已收款作废]]**。
## 典型情境
> [!example] 真实情境
> 周先生在小程序下单 2 张游泳卡 ¥400,准备明天带朋友来游泳。下单后 5 分钟接到朋友电话说出差不来了,他想取消订单。
## 业户视角
### 第 1 步:打开"我的订单"
小程序底部 → 我家 → 我的订单
### 第 2 步:找到待付款订单
```
我的订单
├── 🟡 待付款
│ └── 游泳卡 × 2 ¥400
│ 订单号 CO-20260525-XXX
│ 下单于 5 分钟前
│ ⏰ 剩余 25 分钟自动取消
│ [立即支付] [取消订单]
└── ✅ 已完成
└── ...
```
### 第 3 步:点"取消订单"
弹出确认框:
```
确认取消订单?
取消后此订单不可恢复,如需购买请重新下单。
[再想想] [确认取消]
```
点"确认取消"。
### 第 4 步:订单消失
```
我的订单
├── 🟡 待付款
│ (空)
└── ✅ 已完成 / ❌ 已取消
└── 游泳卡 × 2 ¥400
状态:已取消
原因:用户主动取消
```
> [!success] 完成
> 您未付款,**不涉及任何退款**。订单从"待付款"列表移除,显示在"已取消"区。
## 业务人员视角
### 几乎不用关心
> [!tip] 全自动
> 业户撤单 → 小程序 API → 后端 `VoidAdHocEventAction` → 完成。**业务人员不参与**。
### 业务人员能看到什么
Filament 后台 → 一次性收费 → 切到"已作废" tab:
```
状态:Voided
meta.voided_at: 2026-05-25 15:42:11
meta.voided_reason: "[业户主动取消] 用户在小程序点击取消"
meta.voided_by: null (业户操作,无运营员工)
```
### 如何区分"业户主动撤单"和"系统超时作废"?
`voided_reason` 前缀:
| 前缀 | 来源 |
|---|---|
| `[业户主动取消] ...` | 业户在小程序点取消 |
| `[订单超时作废] ...` | Scheduled job 自动作废 |
| `[临时收费事件作废] ...` | 业务人员在 Filament 后台手动作废 |
详见 `VoidAdHocEventAction``$reason` 参数处理。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 小程序
participant 系统
业户->>小程序: 我的订单 → 点取消
小程序->>业户: 弹确认框
业户->>小程序: 确认
小程序->>系统: DELETE /api/ad-hoc-events/{id}
系统->>系统: 检查订单是否 Pending
alt 是 Pending
系统->>系统: VoidAdHocEventAction
系统->>系统: AdHocEvent → Voided
系统->>系统: CollectionOrder → Failed
系统->>系统: 写 meta.voided_reason = "[业户主动取消] ..."
系统-->>小程序: 成功
小程序-->>业户: 显示"已取消"
else 已是 Completed
系统-->>小程序: 失败,提示"订单已支付,请走退款"
小程序-->>业户: 提示
end
```
## 常见问题
> [!question] 取消后还能恢复吗?
> **不能**。取消是终态。要继续买,请重新下单。
> [!question] 我已经付款了想取消怎么办?
> 走 [[场景-已收款作废]] —— 但需要**联系物业**(小程序不直接暴露付款后的取消按钮,以防误操作)。
> [!question] 我取消的时候系统说"操作失败"?
> 可能是:
> 1. **订单已超时**:你点取消的瞬间订单刚被系统自动作废了 —— 实际效果一样,刷新页面看
> 2. **网络问题**:重试一次
> 3. **订单已被支付**:支付回调与你的取消操作同时到达,以支付为准
> [!question] 取消会影响我的信用吗?
> 不会。系统**不记录**业户取消次数。
## 与超时作废的对照
| 维度 | 业户主动撤单(本场景)| [[场景-超时未付自动作废\|系统超时作废]] |
|---|---|---|
| 触发方 | 业户 | 系统(scheduled job)|
| 时间窗 | 任何时候(只要未付)| 超过 expires_at |
| meta.voided_by | null | null |
| 业户感知 | 主动,即时反馈 | 被动,登录小程序才发现 |
| 适用场景 | 业户明确不想要 | 业户忘记付 |
两种情况**底层都走 `VoidAdHocEventAction`** —— 同一份级联废逻辑,只是触发来源不同。
## 相关概念
- [[概念-AdHocEvent状态机]] — Pending → Voided 流转
- [[概念-CollectionOrder与Receipt]] — Pending 单作废时收据未生成,无需处理
- [[场景-B流-小程序下单+微信支付]] — 上游下单流程
- [[场景-超时未付自动作废]] — 系统自动版本
- [[场景-已收款作废]] — 已支付场景

View File

@@ -0,0 +1,204 @@
---
title: prop-acc · 场景 - 配置 - 新增收费项目
aliases:
- 场景 - 配置 - 新增收费项目
- 场景-配置-新增收费项目
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 配置准备
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:新增收费项目
物业要**开始售卖一种新东西**(比如夏季新增"亲子游泳课程券" / 增加"宠物登记牌"等)。需要先在系统里**配置一个新的收费项目**(`RatePlan`),业务人员才能在 Filament 后台和小程序里见到这个项目。
> [!info] 这是配置任务,不是日常操作
> 一般由**物业管理员 / 运营**做,**不是前台日常**。但所有业务人员都该理解流程,因为新项目上线后他们才能录单。
## 典型情境
> [!example] 真实情境
> 鸿基物业 5 月份决定夏季新增"亲子游泳课程":
> - 单次 ¥80(家长 + 1 个小孩)
> - 月卡 ¥600(每周 2 次)
> - 季卡 ¥1500
>
> 运营经理周一上线前要把这 3 个项目配进系统。
## 业务人员视角
### 第 1 步:与运营 / 财务对齐
新增项目前确认:
| 字段 | 谁决定 |
|---|---|
| 项目名称 | 运营(对外宣传)|
| 单价 | 运营 + 财务(成本核算)|
| **费用类型分类**(FeeType)| 财务(影响会计科目映射)|
| 单位 | 运营("张 / 次 / 月 / 季")|
| 计费方式 | 运营(固定金额 / 按数量 / 按用量)|
| 是否打折 | 运营 |
### 第 2 步:管理员后台新建 RatePlan
```
Filament 后台 → 收费配置 → 收费项目 → 新建
```
| 字段 | 填什么 |
|---|---|
| 社区 | 选要上线的社区(可多选 → 多个社区批量创建)|
| 名称 | "亲子游泳课程 - 单次" |
| 费用类型 | 选"康体活动"(或新建分类) |
| 计费方式 | 固定金额 |
| 单价 | 80 |
| 单位 | 次 |
| 是否启用 | ✅ |
| 备注 | 上线日期 / 课程时间 / 注意事项 |
### 第 3 步:重复创建月卡 / 季卡
类似第 2 步,**3 个项目分别创建**:
- 亲子游泳课程 - 单次 ¥80
- 亲子游泳课程 - 月卡 ¥600
- 亲子游泳课程 - 季卡 ¥1500
### 第 4 步:小程序展示(B 流)
> [!info] 自动同步
> RatePlan 创建后,小程序**自动从同一张表读项目列表**,无需额外配置。**保存即上线**。
### 第 5 步:培训业务人员
```
1. 通知前台员工:"6 月 1 日上线,这是 3 个新项目"
2. 培训:
├── 怎么在 Filament 后台录入(其实和 IC 卡完全一样)
├── 价格 / 适用对象 / 课程时间
└── 业户常见问题怎么答
3. 周日打印一份"项目说明"贴前台,方便临时翻
```
### 第 6 步:监控前几天
```
- 第 1-3 天:留心系统是否报错
- 第 1 周:观察实际售卖情况
- 与运营对齐:是否调价、是否加新项目
```
## 系统流程
```mermaid
sequenceDiagram
participant 运营
participant 财务
participant 管理员
participant 后台
participant 前台员工
participant 小程序
participant 业户
Note over 运营,财务: 上线前准备
运营->>财务: 新项目方案 + 单价
财务-->>运营: 确认费用类型映射 + 入账规则
管理员->>后台: 创建 RatePlan x 3
后台-->>管理员: ✅ 项目已启用
Note over 后台,小程序: 自动同步
管理员->>前台员工: 培训新项目
Note over 业户: 上线日
业户->>小程序: 看到新项目可选
业户->>前台员工: 也可来前台买
前台员工->>后台: 录单(同 IC 卡流程)
```
## 几个重要概念
### RatePlan vs AdHocEvent
> [!info] 关系
> - **RatePlan**(收费项目):**项目定义**。"亲子游泳课程 - 单次" 是 1 个 RatePlan。
> - **AdHocEvent**(一次性收费事件):**单笔交易**。某业户买了 1 张课程券 = 1 个 AdHocEvent,关联到对应的 RatePlan。
>
> 1 个 RatePlan 对应 **N 个 AdHocEvent**(售卖多少笔)。
### FeeType(费用类型)
> [!info] 会计科目分类
> RatePlan 的 `fee_type_id` 决定**会计科目映射** —— 收的钱进哪个会计科目。
>
> 常见 FeeType:
> - 物业费(主营业务收入)
> - 水电气费(代收代缴)
> - **康体活动**(其他业务收入)← 亲子游泳课程在这
> - 装修管理费(其他业务收入)
> - **门禁配套** ← IC 卡在这
>
> FeeType 的设置影响财务月度报表 + 凭证生成(凭证模块,待补)。
## 常见问题
> [!question] 新增项目能上线前测试一下吗?
> 可以。建议:
> - 测试社区(如有)创建 RatePlan
> - 测试账号(运营 / 财务 + 1 个业户测试号)
> - 业户测试号在小程序下单 + 付款 + 收据
> - 测试通过再正式社区上线
> [!question] 一次性配置多个社区怎么操作?
> Filament 后台新建 RatePlan 时,**社区字段是多选**。一次保存可在多个社区同步创建。
> [!question] 已上线的项目想改价格?
> Filament 后台**直接编辑 RatePlan 的单价**。**改价不影响历史订单**(历史订单已冻结当时金额)。新订单按新价。
> [!question] 已上线的项目想停止销售但不删除?
> 把 RatePlan 的 `is_active` 改为 `false`(禁用)。详见 [[场景-配置-下架收费项目并处理Pending单]]。
> [!question] 业务上要求"老人优惠 70% 折扣"怎么配?
> 当前 RatePlan **没有"用户身份折扣"功能**。变通方案:
> - 创建两个 RatePlan:"亲子游泳课程 - 单次"(¥80) + "亲子游泳课程 - 老人优惠"(¥56)
> - 前台员工根据业户年龄选对的项目
>
> 长期方案:实现优惠规则引擎(挂 TODO,等需求量大再做)。
> [!question] 业务上要求"前 100 人 8 折"怎么配?
> 当前**完全不支持**(需要限购 + 计数功能)。挂 TODO。变通方案:运营手动统计,人工调整。
## 上线检查清单
```
□ RatePlan 已创建(单次 / 月卡 / 季卡)
□ 价格与运营确认一致
□ FeeType 与财务确认正确
□ 测试社区跑通(可选)
□ 前台员工已培训
□ 前台贴出"项目说明"
□ 小程序已能看到项目
□ 应急:发现问题怎么联系管理员
```
## 相关概念
- [[概念-CollectionOrder与Receipt]] — RatePlan 影响订单生成
- [[场景-A流-前台购买IC卡]] — 业务人员录单的标准流程
- [[场景-B流-小程序下单+微信支付]] — 小程序自动展示
- [[场景-配置-下架收费项目并处理Pending单]] — 停售流程
## 异常分支
- 上线后发现价格错 → 立刻禁用 + 修改 + 启用
- 业户已下单的旧价不变(系统冻结) → 没问题,新订单走新价

View File

@@ -0,0 +1,236 @@
---
title: prop-acc · 场景 - 配置 - 下架收费项目并处理 Pending 单
aliases:
- 场景 - 配置 - 下架收费项目并处理 Pending 单
- 场景-配置-下架收费项目并处理Pending单
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 配置准备
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:下架收费项目并处理 Pending 单
物业要**停止销售某个收费项目**(夏季泳池关闭、活动结束、产品退市)。系统配置可以一键禁用,但**已有的 Pending 单要单独处理**,否则业户会困惑。
## 典型情境
> [!example] 真实情境
> 9 月初,夏季泳池关闭,"亲子游泳课程 - 单次 ¥80" 不再销售。
>
> - 系统里**已有 3 笔 Pending 订单**(业户在 8 月末下了单但还没付款)
> - 业户上小程序点开会看到"该项目已下架,请联系物业"
## 业务人员视角
### 完整下架流程
```
1. 禁用 RatePlan(停止上架)
2. 处理已有 Pending 单(主动联系业户)
3. 不动已 Completed 订单(历史交易完整保留)
4. 通知客户群体(运营公告)
```
### 步骤 1:禁用 RatePlan
```
Filament 后台 → 收费配置 → 收费项目
├── 找到"亲子游泳课程 - 单次"
├── 编辑 → is_active 改为 ❌ false
└── 保存
```
**效果**:
- 小程序**不再展示**这个项目(已下单的不受影响)
- Filament 后台前台**录新单时找不到这个项目**(只显示活跃的 RatePlan)
- 历史订单**完全不变**(Completed / Voided / Pending 全保留)
### 步骤 2:处理已有 Pending 单
```sql
-- 找到所有相关 Pending 单
SELECT
ahe.id,
ahe.community_user_profile_id,
ahe.amount,
cup.user_id,
u.name AS ,
u.phone
FROM acc_ad_hoc_events ahe
JOIN community_community_user_profiles cup ON ahe.community_user_profile_id = cup.id
JOIN users u ON cup.user_id = u.id
WHERE ahe.rate_plan_id = (SELECT id FROM acc_rate_plans WHERE name = '亲子游泳课程 - 单次')
AND ahe.status = 'pending';
```
输出例:
```
id 业户名 手机号 金额 创建时间
105 李XX 138-XXXX-1234 80 2026-08-28
108 王XX 138-XXXX-5678 80 2026-08-29
112 陈XX 138-XXXX-9012 80 2026-08-30
```
### 步骤 3:逐一联系业户
```
对每笔 Pending 单:
1. 微信 / 电话联系业户
2. 告知"亲子游泳课程已下架,您还未付款的订单 CO-XXX 怎么处理"
3. 业户选择:
├── 不要了 → 立即取消订单([[场景-取消-业户改主意主动撤单]])
└── 还想要 → 婉拒(项目已下架),业户撤单
4. Filament 后台 → 走 VoidAction 作废
├── 作废原因写:"[项目下架] 亲子游泳课程已停售,业户 LXX 同意取消"
└── 提交
```
> [!warning] 不要等"自动超时"自然作废
> 自然超时虽然会废,但业户**等到 30 分钟后才发现**,体验差。**主动联系 + 提前作废** 是友好做法。
### 步骤 4:处理已 Completed 的订单
> [!success] 不需要做任何事
> 历史 Completed 订单**完整保留**:
> - 业户已收到的服务正常使用
> - 收据依然有效
> - 财务月度数据正常
>
> 项目下架**不溯及既往**。
### 步骤 5:发运营公告
```
通过小程序 / 公众号 / 业主群发公告:
"亲爱的业主朋友们:
由于夏季结束,「亲子游泳课程」自 9 月 1 日起停止销售。
已购买的业主可继续使用至有效期满。
8 月 31 日前未付款的订单将自动取消,请有疑问联系物业前台。
感谢您的支持!
鸿基物业服务中心
2026-09-01"
```
## 与新增项目的对照
| 维度 | [[场景-配置-新增收费项目\|新增]] | 下架(本场景) |
|---|---|---|
| 谁操作 | 管理员 | 管理员 |
| 系统改动 | 创建 RatePlan | RatePlan.is_active = false |
| 对历史订单 | 无影响 | 无影响 |
| **对 Pending 单** | 无(新项目无 Pending)| **必须主动处理**(联系业户撤单) |
| **客户沟通** | 上线公告 | **下架公告 + 一对一通知 Pending 业户** |
| 培训 | 业务人员 | 业务人员(知道为啥找不到了) |
## 系统流程
```mermaid
sequenceDiagram
participant 运营
participant 管理员
participant 后台
participant Pending业户
participant 业务人员
运营->>管理员: 停售决定 + 生效日期
管理员->>后台: 禁用 RatePlan
后台-->>管理员: ✅ is_active = false
后台-->>后台: 小程序自动隐藏项目
管理员->>后台: 查 Pending 单
后台-->>管理员: 3 笔待处理
管理员->>业务人员: 转交 3 笔的业户联系信息
loop 对每笔 Pending 单
业务人员->>Pending业户: 微信/电话联系
Pending业户-->>业务人员: 同意取消
业务人员->>后台: VoidAction (reason="项目下架")
后台->>后台: 订单 → Voided
end
管理员->>运营: 发下架公告
```
## 几种下架的边界情况
### 边界情况 1:有未发货的 Completed 订单
业户已付款 + 物业还没发货(走 [[场景-异常-支付完成但实物发不出]]) → **必须继续履约**:
```
1. 项目虽下架,但已收的钱要兑现承诺
2. 物业继续提供服务给已付款业户
3. 不需要 / 不能作废这些 Completed 订单
```
### 边界情况 2:业户要求继续下单
```
业户:"我老婆 9 月 5 日生日,想买课程券作礼物"
业务人员:"很抱歉,这个项目已经下架了,我们 10 月份会有秋季新课程..."
```
下架后**绝对不能为单个业户复活项目** —— 否则其他业户问起来很难解释。**等再开课时正式上架**。
### 边界情况 3:整个 RatePlan 类别下架(夏季所有泳池项目)
```
1. 多个 RatePlan 同时禁用
2. 用 SQL 批量改 is_active = false
3. 对每个 RatePlan 的 Pending 单分别处理
4. 发统一的"夏季泳池关闭"公告
```
### 边界情况 4:数据库还要保留多久?
> [!info] 永久保留
> 即使下架几年,RatePlan 和关联的所有 AdHocEvent / CollectionOrder / Receipt **都不删除**。审计要求 + 业户可能事后查询。
## 常见问题
> [!question] 业户问"我半年前买的月卡能不能延期到下个夏季?"
> 取决于物业政策。**系统不强制有效期** —— 业务人员可以人为协商:
> - 物业愿意延期 → 业户继续使用,系统里不需要任何改动
> - 物业不愿意延期 → 婉拒,告知"原月卡有效期已过"
> [!question] 下架的项目能"复活"吗?
> 能。Filament 后台 → 编辑 → is_active 改回 true。所有历史数据不丢,业户立刻又能在小程序看到。
> [!question] 业户支付**正好与禁用同时发生**怎么办?
> 极少见的竞争场景。系统侧:
> - 业户付款 → 支付回调到达
> - 此时 RatePlan 已禁用,但**订单关联的 RatePlan 数据库引用不会消失**
> - 订单照常翻 Completed,业户拿到收据
>
> 业务侧:业务人员发现这种情况,**主动联系业户** + 提供服务(物业道义责任)。
> [!question] 如何避免业务人员"误删 RatePlan"导致历史数据丢失?
> 当前 Filament 后台**支持 RatePlan 删除**(物理删除)。**应该禁掉这个 UI 入口**,只允许禁用(is_active=false)。挂 TODO。
> [!question] 大批量下架 + 大量 Pending 业户,人工联系不过来怎么办?
> 可以**先群发通知** + 等 30 分钟自动作废。但**有现金价值的 Pending 单**(业户已经在前台付了一半钱的)还是要 1 对 1 沟通。
## 相关概念
- [[场景-配置-新增收费项目]] — 上架的反向流程
- [[场景-取消-业户改主意主动撤单]] — Pending 单的标准撤单流程
- [[场景-异常-支付完成但实物发不出]] — 已 Completed 订单的处理
- [[场景-审计-月底现金对账]] — 下架月份的对账
## 异常分支
- 已 Completed 但未发货 → 继续兑现服务
- Pending 业户突然失联 → 等自动超时作废
- 业务人员误禁用 → 立刻启用,无影响

View File

@@ -0,0 +1,168 @@
---
title: prop-acc · 场景 - 跨渠道补缴
aliases:
- 场景 - 跨渠道补缴
- 场景-跨渠道补缴
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- A流
- B流
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:跨渠道补缴
**儿女在小程序帮老人下单,老人到前台付现金**
这是 [[概念-A流与B流|A 流和 B 流]]并存设计**最有价值的副产物**。其他物业系统通常做不到 —— 因为他们的"线上单"和"线下单"是两个独立流程,互不相通。
## 典型情境
> [!example] 真实情境
> 李女士的妈妈(78 岁)住在北京小区,装修工人下周要进场,需要 5 张装修出入证。
>
> 李女士在上海工作,不能亲自去物业,但她**能在小程序上下单**,妈妈**只需要拿着身份证到前台付现金取证**。
## 业户视角(您要做什么)
### 第 1 步:儿女在小程序下单
(在上海)李女士打开物业小程序:
- 选项目:装修出入证 × 5
- 单价 ¥10,合计 ¥50
- 备注:"我妈下周二上午去取,身份证号 XXX"
- 提交下单(不付款)
> [!info] 关键
> **下单时不付款** —— 系统给一个订单号(CO-xxx)。订单状态:`Pending`,**默认有效期可以延长**(比如 7 天,后台可配)。
李女士把订单号微信发给妈妈,告诉她:"妈,这是订单号,你拿着去前台说。"
### 第 2 步:老人到前台
(在北京)妈妈拿身份证 + 现金 ¥50 去物业前台:
"我女儿在小程序订了 5 张装修证,订单号是 CO-20260525-XX。我来付钱拿证。"
### 第 3 步:前台核对 + 收款
职员在 Filament 后台搜订单号:
- 找到 Pending 订单 CO-XXX,业户名是李女士妈妈,5 张装修证 ¥50 ✅
- 点击"标记已收款" → 选支付方式"现金" → 提交
订单瞬间翻 Completed,收据生成。
### 第 4 步:老人拿证 + 收据
- 5 张装修出入证当场交付
- 收据可打印纸质或发到女儿微信(收据本身归属业户档案,任意指定接收方)
> [!success] 完成
> 全程业户体验流畅:**线上方便、线下办成**。家庭场景里没有谁需要懂"系统怎么工作"。
## 业务人员视角
### 关键操作
```
Filament 后台 → 一次性收费列表
├── 切到 "待付款" tab(默认只看 Completed)
├── 搜业户名 / 订单号
└── 找到记录后,点行操作菜单
└── "标记已收款" 按钮(MarkAdHocEventPaidAction)
├── Modal 弹出:选支付方式(现金/微信/POS)
└── 提交
```
### 业务人员需要核对
> [!warning] 务必核对
> 1. **业户身份**:身份证 vs 系统里登记的业户姓名是否一致
> 2. **金额**:订单冻结金额 vs 业户实付现金是否一致
> 3. **明细**:是不是业户本人订的(避免别人冒领)
### 后台技术细节
```mermaid
sequenceDiagram
participant 儿女
participant 小程序
participant 系统
participant 老人
participant 前台
儿女->>小程序: 帮妈妈下单 5 张装修证
小程序->>系统: CreatePendingAdHocEventAction
系统->>系统: 建 AdHocEvent(Pending) + CO(Pending, expires_at=7天后)
系统-->>小程序: 返订单号 CO-xxx
小程序-->>儿女: 显示订单号
儿女-->>老人: 微信发订单号
Note over 老人,前台: 几天后,老人到前台
老人->>前台: 出示订单号 + 身份证 + 现金
前台->>系统: 搜订单号
系统-->>前台: 显示订单详情
前台->>系统: 标记已收款 + 选"现金"
系统->>系统: MarkAdHocEventPaidAction
系统->>系统: 1. 补 CO 支付字段
系统->>系统: 2. 翻 CO + AdHocEvent → Completed
系统->>系统: 3. 触发 CollectionOrderCompleted
系统->>系统: 4. 自动生成 Receipt
系统-->>前台: 完成通知
前台->>老人: 出装修证 + 给收据
```
## 为什么这个场景重要?
> [!tip] 业务价值
> 中国家庭真实写照:**子女在外地工作,老人留守原小区**。物业要服务老人,但年轻人想用便利渠道帮忙。
>
> 传统物业系统强迫家庭"二选一"(要么子女线上全部办完含付款 / 要么老人现场全部办完),**本系统让线上线下衔接无缝**。
## 常见问题
> [!question] 订单号丢了怎么办?
> 前台可以用**业户姓名 + 身份证号**搜系统里所有 Pending 单。
> [!question] 儿女下单时填错了金额怎么办?
> 老人到前台时,职员发现金额不对,可以**作废原单**(走 [[场景-已收款作废]] 的轻量版,Pending 单作废没收据可废),让儿女或老人在前台**直接重新下一单 A 流**。
> [!question] 跨城市可以吗?
> 完全可以。订单是物业系统里的数据,不绑定地理位置。儿女在哪个国家都行,只要老人到对应小区物业即可。
> [!question] 多人同时帮老人下单怎么办?
> 老人会在系统里有**多个 Pending 单**。前台核对时一一处理,**支付一笔结一笔**。
## 业户的"双向感觉"
```mermaid
journey
title 业户体验地图
section 儿女(线上视角)
下单: 5: 儿女
看到订单号: 5: 儿女
不需付款: 5: 儿女
不需关注后续: 4: 儿女
section 老人(线下视角)
拿订单号到前台: 5: 老人
付现金: 4: 老人
当场拿货: 5: 老人
纸质收据: 5: 老人
```
## 相关概念
- [[概念-A流与B流]] — 共用一套表的关键设计决定
- [[概念-CollectionOrder与Receipt]] — 订单状态如何流转
- [[概念-AdHocEvent状态机]] — Pending → Completed
- [[场景-B流-小程序下单+微信支付]] — 对比标准 B 流

View File

@@ -0,0 +1,181 @@
---
title: prop-acc · 场景 - 异常 - 同业户跨社区 Pending 单
aliases:
- 场景 - 异常 - 同业户跨社区 Pending 单
- 场景-异常-同业户跨社区Pending单
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 异常故障
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:同业户跨社区 Pending 单
业户在**多个社区**(物业项目)都有房子,小程序里能下单**任一社区**的一次性收费。可能产生跨社区的待付单 + 跨渠道补缴的复杂场景。
> [!info] 不算 bug,但需要业务人员理解
> 本系统天然按**社区(community_id)隔离数据**。但同一个业户在多社区有不同房子时,他/她的订单分布在不同社区的数据空间。
## 典型情境
> [!example] 真实情境
> 周先生是连锁老板,**北京有住宅、上海有公寓**,两个小区都是同一物业公司"鸿基物业"管理。
>
> 一个周末他在北京住宅的小程序下单 IC 卡 ¥30(没付),又在上海公寓的小程序下单装修证 ¥150(没付)。
>
> 第二天他到**北京物业前台**问"我下了什么订单都还没付的?",职员只能查到**北京小区**的 1 笔。
## 业务人员视角
### 关键约束:**Filament 默认只显示当前社区**
```
登录 Filament → 切换社区(顶栏选择器)
├── 北京小区 → 看到周先生的 IC 卡订单
├── 上海小区 → 看到周先生的装修证订单
└── 切换社区 → 看不到另一社区的订单
```
### 如何帮业户查全部跨社区订单
**步骤 1:理论上的全局视角**
```sql
-- 数据库查询(超级管理员视角)
SELECT
ahe.id,
ahe.community_id,
c.name AS ,
rp.name AS ,
ahe.amount,
ahe.status,
ahe.created_at
FROM acc_ad_hoc_events ahe
JOIN community_communities c ON ahe.community_id = c.id
JOIN acc_rate_plans rp ON ahe.rate_plan_id = rp.id
WHERE ahe.community_user_profile_id = (
SELECT id FROM community_community_user_profiles
WHERE user_id = (SELECT id FROM users WHERE phone = '13800138000')
)
AND ahe.status = 'pending';
```
**步骤 2:实际操作**
> [!warning] 普通业务人员通常无法跨社区查询
> 物业前台员工只能登录自己负责的社区。**跨社区查询需要总部管理员**。
>
> 业务流程上的应急方案:
> - 业户在哪个社区前台,就办哪个社区的订单
> - 让业户**自己去另一个社区的小程序入口**查另一笔订单
> - 集团总部如有需要可以**总部协调跨社区客服**
### 数据隔离的好处和代价
> [!success] 好处:数据干净
> - 北京小区的财务对账只看北京数据
> - 上海小区的财务对账只看上海数据
> - 互不影响 = 各社区独立运营
> [!warning] 代价:跨社区业户体验差
> - 跨社区业户感受不到"统一"
> - 前台无法跨社区帮业户查订单
> - 需要业户**自己记得在哪个社区下了什么单**
## 数据库设计的隔离机制
```mermaid
graph TD
A[全国业户档案<br/>users 表] -->|user_id| B[业户在北京<br/>CUP id=100]
A -->|user_id| C[业户在上海<br/>CUP id=200]
B -->|community_user_profile_id| D[北京 IC 卡订单<br/>community_id=1]
C -->|community_user_profile_id| E[上海 装修证订单<br/>community_id=2]
F[北京前台<br/>登录到 community_id=1] -.->|看不到| E
G[上海前台<br/>登录到 community_id=2] -.->|看不到| D
classDef user fill:#fef3c7
classDef profile fill:#dbeafe
classDef order fill:#dcfce7
classDef frontdesk fill:#fee2e2
class A user
class B,C profile
class D,E order
class F,G frontdesk
```
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 北京小程序
participant 北京前台
participant 上海小程序
participant 上海前台
participant 系统
业户->>北京小程序: 下单 IC 卡
北京小程序->>系统: 建 Pending 单 (community_id=1)
业户->>上海小程序: 下单装修证
上海小程序->>系统: 建 Pending 单 (community_id=2)
Note over 业户: 第二天到北京前台
业户->>北京前台: 我的所有待付单是?
北京前台->>系统: 查 community_id=1
系统-->>北京前台: 只返回北京 IC 卡单
北京前台-->>业户: 您有 1 笔待付:IC 卡
Note over 业户: 业户困惑:"我记得还有一笔啊"
业户->>业户: 想起来 → 去上海小程序查
业户->>上海小程序: 查我的订单
上海小程序-->>业户: 找到上海装修证单
```
## 常见问题
> [!question] 业户能在北京小程序里看到上海订单吗?
> **不能**。小程序默认按当前社区隔离。业户切换社区才能看另一社区的订单。
> [!question] 如果是集团连锁物业,有"统一业户视图"吗?
> 当前**没有**。如果业务方明确需要,可以挂 TODO 做一个"业户中心"页面,跨社区聚合该业户的所有订单。**优先级看实际需求**。
> [!question] 跨社区补缴可以吗?
> **不能**。北京 Pending 单**只能在北京前台**用现金补缴。上海前台搜不到这笔订单。
> [!question] 业户回家发现两笔都到期了,怎么办?
> 两笔都自动作废,业户**重新在对应社区下单**即可。详见 [[场景-超时未付自动作废]]。
> [!question] 同一业户在 5 个社区都有房,管理上会乱吗?
> 业户需要**自己管理**(记录每个社区的房号、订单)。这是"多社区业户"的固有复杂性,不只是本系统的问题 —— 物业管理本质如此。
## 跨社区业户的常见需求与方案
| 需求 | 当前方案 | 长期方案 |
|---|---|---|
| 跨社区查所有订单 | 业户自己切社区查 | 业户中心(挂 TODO)|
| 跨社区合并支付 | 不支持 | 支付聚合(技术复杂,挂 TODO)|
| 跨社区合并发票 | 不支持(发票本来就独立)| 发票合并(财务侧支持)|
| 跨社区免重复绑定 | 系统已支持(同 user_id 自动关联)| 已实现 ✅ |
## 相关概念
- [[概念-CollectionOrder与Receipt]] — 每笔订单绑定 community_id
- [[场景-跨渠道补缴]] — 同社区内的跨渠道场景
- [[场景-超时未付自动作废]] — Pending 单的统一生命周期
## 异常分支
- 业户记不清在哪个社区下的单 → 集团总部协助查询
- 业户希望取消所有未付单 → 在各社区小程序逐一取消

View File

@@ -0,0 +1,167 @@
---
title: prop-acc · 场景 - 异常 - 业户重复下单
aliases:
- 场景 - 异常 - 业户重复下单
- 场景-异常-业户重复下单
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 异常故障
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:业户重复下单
业户在小程序里**同一项目下了多笔订单**,可能是误操作、可能是网络不畅以为没下成功。
## 典型情境
> [!example] 情境 1:网络卡顿
> 周三下午,陈先生小程序下单游泳卡 ¥200。点完"下单"按钮后**页面卡了 5 秒没反应**,他不耐烦又点了一次。
>
> 5 秒后,**系统里有两笔 Pending 订单**。
> [!example] 情境 2:误操作
> 王女士下单后,**手机退到后台又重新打开**,看到一笔"待付款"以为是上次没付的旧单,又点了"重新下单"。
>
> 实际上系统里**第一笔单还在 Pending**,她又下了第二笔。
> [!example] 情境 3:批量场景
> 装修公司下单 8 张装修证,然后**忘了已经下过**,5 分钟后又下了 8 张。
>
> 系统里现在有 16 张待付款的装修证 + 16 个 CollectionOrder。
## 业户视角
### 您看到什么
打开小程序"我的订单 → 待付款":
```
🟡 待付款
├── 游泳卡 × 1 ¥200
│ 下单于 10:05
│ [立即支付] [取消订单]
└── 游泳卡 × 1 ¥200 ← 重复的!
下单于 10:05
[立即支付] [取消订单]
```
### 您应该怎么办
> [!tip] 简单选择
> - **只付 1 笔**(选你认为有效的那笔,通常是早的)
> - **取消另 1 笔**(走 [[场景-取消-业户改主意主动撤单]])
> - 另 1 笔不取消也行,**30 分钟后系统自动作废**
> [!warning] 千万不要"为了保险都付了"
> 都付了 → 系统记两笔有效订单 → 你被扣两次钱。要退款要联系物业,流程慢。**只付 1 笔 + 取消另 1 笔** 最干净。
## 业务人员视角
### 业户来问"我下了几个订单不知道是不是都有效"
```
1. Filament 后台 → 搜业户姓名 / 手机号
2. 切到"待付款 (Pending)" tab
3. 看是否有同一项目的多笔 Pending 单
4. 与业户确认:
├── 想要 1 笔 → 留 1 笔,作废其余
└── 全部要 → 不动,让业户每笔单独支付
5. 作废多余的 Pending 单(走 [[场景-取消-业户改主意主动撤单|主动撤单流程]])
```
### 如果业户已经把多笔都付了
```
1. 确认哪几笔是"真的要"、哪几笔是"重复多余的"
2. 多余的走 [[场景-已收款作废]]
├── 作废订单 + 收据
└── 退款(微信 / 现金 / POS)
3. 给业户确认"已退 X 元到您原微信账户"
```
## 系统视角:为什么没自动防重?
> [!info] 系统**故意不防**
> 原因:**有些业务场景就是要重复下单**!例如:
> - 业户买 3 张游泳卡分给家人,**故意拆 3 笔**(便于送人时给收据)
> - 业户买 IC 卡当礼物,要拿 5 张不同收据
>
> **系统无法判断**"这是误操作的重复" vs "故意拆笔",所以**不做自动拦截**。
### 前端小程序的弱防护
> [!tip] 建议小程序层做防抖
> 业户连点 "下单" 按钮,小程序应该:
> - 第一次点击后**禁用按钮 2 秒**
> - 显示 loading,防止重复点
> - 但不做"15 秒内不允许同样订单"硬性限制(会误伤合理场景)
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 小程序
participant 系统
业户->>小程序: 第 1 次点"下单"
小程序->>系统: POST /api/ad-hoc-events
Note over 系统: 网络卡顿,响应延迟
系统-->>小程序: ✅ 订单 1 创建
业户->>小程序: 第 2 次点"下单" (误以为第一次没成功)
小程序->>系统: POST /api/ad-hoc-events
系统-->>小程序: ✅ 订单 2 创建
Note over 业户: 业户切到"我的订单"
业户->>小程序: 看到 2 笔 Pending
业户->>业户: 困惑
Note over 业户: 推荐:取消 1 笔
业户->>小程序: 取消订单 2
小程序->>系统: DELETE /api/ad-hoc-events/{order-2}
系统->>系统: VoidAdHocEventAction
业户->>小程序: 支付订单 1
小程序->>系统: 完成订单 1
```
## 常见问题
> [!question] 系统能不能做"30 秒内不允许同一业户下同样订单"?
> 技术上可以加。但会误伤"故意拆笔"的场景(业户为家人买、要多张收据)。**当前选择不做硬限制**,靠 UI 弱防护(按钮防抖)+ 业务人员人工处理已经够。
> [!question] 一个业户最多能有多少笔 Pending 单?
> **无上限**。但**单超过 100 笔的业户**会触发反爬虫(虽然当前没装) —— 这种通常是 API 误用 / 攻击场景,与正常业户无关。
> [!question] 业户重复下单影响库存吗?
> 当前**系统不管物理库存**(IC 卡库存盒、装修证存货数)。库存管理是物业内部独立流程。重复下单只是**数据库里多了几笔记录**,实物没消耗。
> [!question] 业户付了 2 笔重复订单,2 笔都生成了收据,财务对账时会发现吗?
> 会发现 —— 月底对账时,**同一业户同一时段 2 笔同样金额** 会引起注意。建议:
> - 业务人员主动联系业户确认
> - 不论是否重复都按收据数对账
> - **物业可以发起退款**(走 [[场景-已收款作废]] 作废其中 1 笔)
## 相关概念
- [[概念-AdHocEvent状态机]] — 每笔订单独立的状态
- [[场景-取消-业户改主意主动撤单]] — 撤销多余订单
- [[场景-已收款作废]] — 已付款的多余订单怎么退
- [[场景-超时未付自动作废]] — 未付款的多余订单会自动废
## 异常分支
- 全部都付了 → [[场景-已收款作废]] 退多余的
- 业户坚持要全部 → 系统照单处理,留每笔独立收据

View File

@@ -0,0 +1,160 @@
---
title: prop-acc · 场景 - 异常 - 支付完成但实物发不出
aliases:
- 场景 - 异常 - 支付完成但实物发不出
- 场景-异常-支付完成但实物发不出
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 异常故障
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:支付完成但实物发不出
业户**钱已经付了**,但物业**无法当场交付实物**(IC 卡缺货、装修证用完、泳票打印机坏)。
## 典型情境
> [!example] 情境 1:IC 卡缺货
> 业户付了 ¥30 买 IC 卡,职员去拿卡发现工本卡盒空了(下一批要 3 天后才到)。
>
> → 业户已经付钱了,卡当场拿不到。
> [!example] 情境 2:打印机坏
> 业户付完游泳票钱,前台打印机卡纸,纸质票出不来。
>
> → 业户已经付钱了,纸质票当场拿不到。
> [!example] 情境 3:装修证人脸照片采集设备故障
> 业户付完装修证钱,采集工人人脸照片的设备故障。
>
> → 业户已经付钱了,出入证制作不了。
## 业户视角
### 您能选两条路
> [!tip] 路线 A:等
> 物业承诺**X 天内补发**,您下次来或物业送到您家。
> - 钱不退,订单状态依然 Completed
> - 物业**口头/微信承诺** 但不在系统里改任何东西
> [!tip] 路线 B:退
> 您当场说"算了,我退钱不要了"。
> - 走 [[场景-已收款作废]] 流程
> - 钱退给您
> - 订单作废
**业户体验差异**:
- 路线 A:不退钱,但要相信物业 "几天后补"
- 路线 B:钱拿回来,自己改天再来或转去别处买
## 业务人员视角
### 推荐处理流程
```
1. 第一时间承认问题,**当面致歉**
"不好意思阿姨,这批 IC 卡正好用完了,新货要 3 天后到。"
2. 给业户两个选项:
├── 路线 A:登记 + 承诺(信任成本低,业户感觉好)
└── 路线 B:立刻退款(钱安全,但流程多)
3. 业户选 A:
├── 在内部"待补发"清单登记:
│ - 订单号 CO-XXX
│ - 业户名 + 电话
│ - 承诺日期
├── 系统里订单**不需要任何改动**
├── 几天后货到:
│ - 通知业户来取
│ - 业户来取,核对订单号 + 给货
│ - **系统里依然不需要任何改动**(订单已 Completed)
4. 业户选 B:
├── 走 [[场景-已收款作废]] 作废订单
├── 退还现金 / 微信退款
└── 业户离开
```
### "待补发清单"建议
> [!warning] 系统外的事但很重要
> 系统不管"业户付了钱但还没拿货"。物业需要**自己维护一份补发清单**(Excel / 小程序待办 / 物业群通知都行)。
>
> 关键字段:
> - 订单号(便于反查)
> - 业户姓名 + 电话(便于联系)
> - 承诺补发时间
> - 实际补发时间(已补发后填)
> - 责任人(谁负责跟进)
### 路线 A 的财务一致性
> [!success] 钱货分离对账上没问题
> 业户付了钱、订单 Completed → 系统记录已收款。
> 业户拿货发生在几天后 → 不影响财务记录(系统只管"收钱"这一步)。
>
> 月底对账 = 看 CollectionOrder 总额。物理库存盘点是另一个独立流程(超出本系统范围)。
## 系统流程对比
```mermaid
graph TD
A[业户付款] --> B{物业能当场发货?}
B -->|能| C[正常完成<br/>系统无异常]
B -->|不能| D{业户选哪条路?}
D -->|路线 A 等几天| E[系统无改动<br/>物业内部登记]
D -->|路线 B 退钱| F[走 VoidAction<br/>退款]
E --> G[几天后补发<br/>系统无改动]
classDef happy fill:#dcfce7
classDef exception fill:#fef3c7
classDef refund fill:#fee2e2
class A,C happy
class B,D,E,G exception
class F refund
```
## 常见问题
> [!question] 业户选了路线 A,几天后还没拿到货怎么办?
> 物业内部问题。建议:
> - 设置闹钟提醒(承诺日 ± 1 天)
> - 主动联系业户 "您的 IC 卡到了,什么时候来取?"
> - 业户不耐烦了 → 走路线 B 退款
> [!question] 业户选了路线 A,但后来联系不上了怎么办?
> 经过 30 天还联系不上业户:
> - 留个长期备忘录
> - 系统里订单依然 Completed(财务上"已收款已交付"的法律事实)
> - 实物 IC 卡放在物业保管,业户随时可来取
> [!question] 业务人员能在系统里标记"已收款未发货"吗?
> 当前**没有这个状态**。如果需要,可以:
> - 临时方案:在订单 `remark` 字段写"待补发,缺 IC 卡"
> - 长期方案:加一个 `delivery_status` 字段(待补发/已补发),挂 TODO 等需求明确
> [!question] 路线 B 退款时,微信支付几天才退到账,业户在意吗?
> 部分业户会在意。可以**当场垫现金给业户**(¥30 这种小额完全可以),系统里依然走微信退款 —— 业户拿了现金不再焦虑,几天后微信钱也到账了(物业自己消化)。
## 相关概念
- [[概念-CollectionOrder与Receipt]] — 收款记录与物理交付是两件事
- [[场景-已收款作废]] — 路线 B 的基础流程
- [[场景-A流-前台购买IC卡]] — 正向交付流程
## 异常分支(更进一步的异常)
- 业户付完想马上退 → 直接走 [[场景-已收款作废]]
- 路线 A 等了一个月还没货 → 走 [[场景-已收款作废]] 退款

View File

@@ -0,0 +1,138 @@
---
title: prop-acc · 场景 - 异常 - 支付分账失败
aliases:
- 场景 - 异常 - 支付分账失败
- 场景-异常-支付分账失败
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 异常故障
audience:
- 业务人员
status: 草稿
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:支付分账失败
业户付款成功,但**物业商户号到结算账户的分账失败**。属于支付平台异常,本系统侧只能等通知 + 人工干预。
> [!warning] 进阶场景,本系统弱介入
> 分账是**微信/支付宝商户后台**的功能,本系统侧基本看不到这一步。本文档仅作为应急参考。
## 什么是"分账"?
> [!info] 一图看懂
> ```
> 业户付款 → 微信支付收钱 → 微信商户号(物业)→ 分账到物业银行账户
> ✅ 这一步是支付 ✅ 这一步是分账(本场景关心)
> ```
>
> 大多数小型物业**不需要分账**(钱直接从微信结算到对公账户)。**需要分账的场景**:
> - 物业方 + 物业服务集团 + 项目方三家**按比例分钱**
> - 上市物业集团 + 全国各分公司**按地域分账**
> - 委托管理模式(开发商 vs 物业公司 二八分)
## 典型情境
> [!example] 真实情境
> 鸿基物业管理集团旗下小区,业户用小程序付了 ¥3000 装修押金。
>
> 微信支付成功 → 钱进鸿基物业商户号。商户号配置了分账规则:
> - 70% 给小区项目方
> - 30% 给鸿基集团运营费
>
> 第二天集团财务发现:小区项目方收到 ¥2100 ✅,**集团运营费 ¥900 没有收到** ❌。
## 业务人员视角
### 这种问题怎么发现?
业务人员**不会主动发现** —— 通常是:
- 集团财务月底对账 → 发现少了一部分
- 微信商户后台**邮件通知**"分账失败"
> [!warning] 关键
> 系统侧的 `CollectionOrder` **状态依然是 Completed** —— 因为业户支付的钱**确实进了商户号**,只是后续分账失败。系统层面无错。
### 处理流程
```
1. 登录微信支付商户后台 → 分账记录
2. 找到失败的分账记录,看失败原因:
├── 接收方账户冻结
├── 分账方金额不足(剩余金额已分完)
└── 接收方未签约接收能力
3. 联系微信客服 / 修复配置
4. 重试分账 (通常 30 天内可重试)
```
### 本系统侧需要做什么?
**几乎不用** —— 本系统已经"收到了钱"(从业户视角钱付完了)。分账是物业内部账务问题。
> [!info] 但如果分账失败导致需要"全单退款给业户":
> - 业务人员走 [[场景-已收款作废]] 标记订单作废
> - 微信商户后台**手动发起退款**给业户
> - 业户拿回钱,后续物业再处理内部账务
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 微信支付
participant 物业商户号
participant 项目方账户
participant 集团账户
participant 系统
业户->>微信支付: 付款 ¥3000
微信支付->>物业商户号: ¥3000 入账
微信支付->>系统: webhook → MarkAsPaid
系统-->>业户: 订单 Completed,收据生成
Note over 业户,系统: 业户视角:一切正常
Note over 物业商户号: 系统自动触发分账
物业商户号->>项目方账户: 分账 ¥2100 ✅
物业商户号->>集团账户: 分账 ¥900 ❌ (接收方账户冻结)
Note over 业务人员: 第二天集团对账才发现
```
## 常见问题
> [!question] 业户会感知到分账失败吗?
> 不会。从业户视角,**钱付完订单完成**,完美无瑕。
> [!question] 财务多久能发现?
> 取决于对账频率。建议物业**至少每周对一次分账记录**,而不是等月底。
> [!question] 系统能监控分账状态吗?
> 当前**没有集成**。可以挂 TODO:
> - 微信商户号开放分账状态查询 API
> - 系统每天定时查最近 7 天的分账状态
> - 失败的发警报到物业财务
> [!question] 分账失败 30 天没解决,钱会怎样?
> 微信会**原路退回给业户**(钱回到业户原微信)。这种情况业户会突然收到一笔退款,**联系不上业户解释** = 麻烦。所以**分账失败 30 天前必须处理**。
## 简化场景:不需要分账的物业
> [!success] 大多数小型物业:跳过本场景
> 单一物业公司,微信商户号直绑对公账户,**无需分账配置**。本场景对你们不适用。
## 相关概念
- [[概念-CollectionOrder与Receipt]] — 系统侧"收钱"的语义边界
- [[场景-B流-小程序下单+微信支付]] — 业户付款正向流程
- [[场景-审计-月底现金对账]] — 多渠道对账
## 待补
- **系统集成分账状态监控**:挂 TODO,等真正出现分账失败客诉再做
- **多商户/多账户场景的会计科目对接**:超出一次性收费模块范围,与凭证模块相关(待补)

View File

@@ -0,0 +1,196 @@
---
title: prop-acc · 场景 - 异常 - 微信支付回调延迟
aliases:
- 场景 - 异常 - 微信支付回调延迟
- 场景-异常-微信支付回调延迟
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 异常故障
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:微信支付回调延迟
业户**在微信里付款成功**,但**系统订单还停在 Pending 状态**。等几分钟才更新,业户和业务人员都可能误以为出问题了。
## 典型情境
> [!example] 真实情境
> 周日晚上李太太在小程序下单充电桩电费 ¥200,微信支付成功 —— 微信弹窗"已付款"、扣款记录里也看到了。
>
> 但她切回小程序"我的订单",订单状态还是"待付款"。等了 1 分钟没变化,她以为没成功,**又点了一次"立即支付"**。
>
> 微信弹"您已支付过该订单,无需重复支付",这才放心。3 分钟后小程序终于刷新为"已完成"。
## 为什么会延迟?
> [!info] 微信回调链路
> 业户支付 → 微信服务器 → 物业服务器 webhook → 系统更新订单状态。
>
> 任何一步**网络慢、服务器忙、回调队列堆积**,都可能让"系统知道你付款了"晚几秒到几分钟。**99% 的回调在 10 秒内到达**,**1% 可能要 30 秒~5 分钟**,极少数(0.01%)**完全丢失**。
## 业户视角
### 您可能看到的几种状态
| 时间 | 微信侧 | 小程序订单状态 | 您的感觉 |
|---|---|---|---|
| 0-3 秒 | 支付完成 | 仍然显示"待付款" | 正常,刷新一下 |
| 3-30 秒 | 支付完成 | 已变"已完成" | 完美 |
| 30 秒-5 分钟 | 支付完成 | 仍然"待付款" | 怀疑没成功 |
| > 5 分钟 | 支付完成 | 一直"待付款" | 真的有问题 |
### 您应该怎么办
> [!warning] 不要重复支付!
> 微信有重复支付防护(同一订单只能付一次),但万一系统出问题,**重复支付的钱可能很难退**。
**正确步骤**:
1. 看微信"账单 / 钱包"里是否有这笔扣款记录
- ✅ 有 → **钱已经付了**,不要再付
- ❌ 无 → 钱没出去,可以放心重新支付
2. 钱已付但小程序不更新:
- 等 5 分钟
- 下拉刷新小程序订单页
- 还不更新 → 联系物业前台
3. 联系物业前台:
- 告诉他们订单号 + 微信扣款截图
- 物业能在 Filament 后台**手动核实并标记完成**
### 别担心,钱不会丢
> [!success] 双向保障
> - 微信侧:确认扣款,有微信账单为证
> - 物业侧:即使回调彻底丢失,微信商户后台**能看到这笔交易**,物业人工核对后手动入账
## 业务人员视角
### 业户来问"我付了但显示没付"怎么处理?
```
1. 让业户出示微信扣款记录(截图 / 商家订单号)
2. Filament 后台搜业户订单号(CO-xxx)
├── 状态显示 Pending → 回调真的没到
└── 状态已是 Completed → 回调刚到,提示业户刷新页面
3. 状态 Pending 且业户确认已付:
├── 在微信商户后台查这笔交易
│ └── 找到 transaction_id (微信侧订单号)
├── 与系统 CO-xxx 的 order_no 核对
└── 如确认是同一笔:手动标记完成
```
### 手动标记完成
> [!warning] 当前 UI 没有直接的"标记完成"按钮
> 当前只能通过 `MarkAdHocEventPaidAction` 业务方法调用。临时方案:
> - 走 Tinker:`app(MarkAdHocEventPaidAction::class)->handle($event, [...])`
> - 或者在 Filament 后台为业户**重新建一笔**(走 A 流即收即付),把原 Pending 单走作废
>
> 长期方案:**给 ViewAdHocEvent 加一个"手动标记已付款"Action**,挂 TODO。
### 后台技术细节
```mermaid
sequenceDiagram
participant 业户
participant 微信
participant 微信服务器
participant 物业 webhook
participant 系统
participant 业务人员
业户->>微信: 付款 ¥200
微信->>业户: 弹窗"已付款"
微信->>微信服务器: 入账
Note over 微信服务器: 网络/服务器繁忙
微信服务器-->>物业 webhook: ⏳ 延迟 30s ~ 5min ⏳
Note over 业户: 业户看小程序仍显示待付款
业户->>业务人员: 询问"我付了为什么还是待付款"
业务人员->>微信商户后台: 查 transaction_id
业务人员->>系统: 手动 MarkAsPaid
系统->>系统: CollectionOrder + AdHocEvent → Completed
系统-->>业户: 推通知"已付款"
Note over 微信服务器: 几分钟后,延迟回调终于到了
微信服务器->>物业 webhook: 现在才到
物业 webhook->>系统: 检查订单已 Completed → 跳过 (幂等)
```
## 几个关键设计决策
### 1. 回调幂等
> [!info] 系统设计
> webhook 处理时**先查订单状态**:
> - 若是 Pending → 走 MarkAdHocEventPaidAction 完成流程
> - 若已是 Completed → 直接返回成功,不做任何事
> - 若是 Voided → 退回退款流程(钱原路退回业户)
>
> 这样**不论回调到达多少次**,系统都保持一致状态。
### 2. 业户重复支付的处理
如果业户没看到状态更新而**重复点了"立即支付"**:
- 微信端会拦截(同一订单只能付一次)
- 系统侧**不会收到第二笔扣款**
但万一某些渠道允许重复支付(罕见):
- 系统会收到**两笔 transaction_id 不同的回调**
- 第一笔正常处理 → 翻 Completed
- 第二笔到达时 → 系统发现订单已 Completed,**直接对第二笔发起原路退款**
### 3. 超时 vs 回调延迟的竞争
> [!warning] 一个微妙的边界情况
> 业户付款的瞬间正好是订单 expires_at,超时 job 同时跑:
>
> - 超时 job 拿到锁先把订单 → Voided
> - 微信回调晚 1 秒到 → 看到 Voided,触发**原路退款**(钱退回业户)
>
> 业户此时看到"扣款 + 几小时后退款"。这是正常容错行为,不是 bug。
## 常见问题
> [!question] 业户已经离开了,但延迟回调到了,会怎样?
> 系统正常翻 Completed,生成 Receipt。业户**下次打开小程序**就能看到状态更新和收据。无需联系物业。
> [!question] 5 分钟还没到回调,但业户急着要 IC 卡怎么办?
> 走业务人员的"手动标记完成"路径(见上)。**信任微信侧扣款记录优先**。
> [!question] 同一笔订单回调收到 2 次怎么办?
> 幂等设计 → 第二次直接返回成功。详见上述设计决策 1。
> [!question] 物业怎么知道是不是真的"回调丢了"?
> 监控 + 报警:
> - 每天对账微信商户后台 vs 系统订单总数
> - 差额 > 阈值(比如 5 笔)发警报
> - 人工补单(查商户后台 → 手动标记)
## 相关概念
- [[概念-CollectionOrder与Receipt]] — Pending → Completed 流转
- [[概念-AdHocEvent状态机]]
- [[场景-B流-小程序下单+微信支付]] — 正向流程
- [[场景-超时未付自动作废]] — 时间竞争场景
## 异常分支
- 业户付了款但物业拒绝处理 → 走 [[场景-已收款作废]] 退款给业户
- 回调收到但金额对不上 → 数据问题,技术介入

View File

@@ -0,0 +1,139 @@
---
title: prop-acc · 场景 - A 流 - 前台购买 IC 卡
aliases:
- 场景 - A 流 - 前台购买 IC 卡
- 场景-A流-前台购买IC卡
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- A流
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:前台购买 IC 卡
最典型最高频的一次性收费场景。门禁卡、停车卡、电梯卡都走这条路径。
## 典型情境
> [!example] 真实情境
> 张阿姨,72 岁,上周搬家钥匙丢了想配新门禁卡。她不会用小程序,下午 3 点去了物业前台办公室。
## 业户视角(您要做什么)
### 第 1 步:到前台
带上**身份证 + 房产证(或租赁合同)** 到物业前台。
> [!tip] 装修业户特别注意
> 如果您是装修公司,需要带上**业主授权书**或合同复印件。
### 第 2 步:告诉职员要办什么
"我要补办一张门禁卡,房号是 12-3-501。"
### 第 3 步:付款
职员会告诉您**多少钱**(常见 ¥30-50 一张),您可选:
- **现金** —— 最常见
- **微信扫码** —— 职员出示物业收款码
- **POS 刷卡** —— 银行卡支付
### 第 4 步:拿卡 + 收据
- 实物 IC 卡:**当场拿到**
- 收据:可以选**打印纸质**或**微信收**
> [!success] 完成
> 整个过程 5 分钟内搞定。回家就能刷卡进门了。
## 业务人员视角(职员怎么操作)
### 第 1 步:打开后台
登录 Filament 后台 → 一次性收费 → 新建
### 第 2 步:填表单
| 字段 | 填什么 |
|---|---|
| 业户 | 通过手机号或房号查找业户 |
| 收费项目(RatePlan)| 选 "IC 卡 - 门禁" |
| 数量 | 1 |
| 金额 | 自动按 RatePlan 单价填(可手动改)|
| 支付方式 | 现金 / 微信 / POS |
| 收款银行账户 | 微信/POS 选对应银行账户;现金可空 |
| 备注 | 选填,如 "丢卡补办" |
### 第 3 步:提交
点击"创建"。系统瞬间完成:
-`AdHocEvent`(状态 Completed)
-`CollectionOrder`(状态 Completed)
-`Receipt`(状态 Issued)
- 触发收据 PDF 生成
### 第 4 步:出货 + 给收据
- 从抽屉拿一张空白 IC 卡,在制卡机里写入业户房号
- 把卡交给业户
- 把收据打印 / 发到业户微信
## 系统流程(技术视角)
```mermaid
sequenceDiagram
participant 业户
participant 前台
participant Filament
participant 数据库
participant 监听器
业户->>前台: 我要买门禁卡 + 付现金
前台->>Filament: 填表单 + 提交
Filament->>数据库: 开启事务
Filament->>数据库: 1. 建 CollectionOrder (Completed)
Filament->>数据库: 2. 建 AdHocEvent (Completed, 关联 CO)
Filament->>监听器: 3. 触发 CollectionOrderCompleted 事件
监听器->>数据库: 4. 建 Receipt + ReceiptItem
Filament->>数据库: 提交事务
Filament-->>前台: 成功通知
前台->>业户: 出卡 + 给收据
```
> [!info] 一气呵成
> 第 1-4 步在一个数据库事务里完成 —— 任何一步失败,整笔操作回滚,不会出现"扣了钱但没出卡"的半成品状态。
## 常见问题
> [!question] 业户没带身份证可以办吗?
> 各物业政策不同。系统不会强制 —— 是物业内部审核流程。
> [!question] 业户现金不够可以拆分支付吗?
> 当前一笔订单只支持一种支付方式。需要拆,可以分两单做(2 张 IC 卡分两笔录入)。
> [!question] 万一录错金额怎么办?
> 走 [[场景-已收款作废]] 流程,作废后重新录入。
> [!question] 卡的物理库存怎么管?
> 当前系统**不管物理库存**,只管财务记录。需要库存管理可以接外部系统,或挂 TODO 等业务方反馈。
## 相关概念
- [[概念-A流与B流]] — 为什么这叫 A 流
- [[概念-CollectionOrder与Receipt]] — 创建的三件套
- [[概念-AdHocEvent状态机]] — 直接进入 Completed 状态
## 异常分支
- 业户付完反悔 → [[场景-已收款作废]]
- 业户改主意不要了 → 录入前直接放弃,系统里没任何记录

View File

@@ -0,0 +1,136 @@
---
title: prop-acc · 场景 - A 流 - 前台购买泳票
aliases:
- 场景 - A 流 - 前台购买泳票
- 场景-A流-前台购买泳票
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- A流
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:前台购买泳票
夏季高频小额场景。**单次入场票**、**月卡**、**季卡**都按一次性收费处理。
## 典型情境
> [!example] 真实情境
> 周日下午 2 点,小区泳池开放。陈太太带儿子来游泳,直接在泳池前台买票 —— ¥20 单次 × 2 人 = ¥40。
## 业户视角
### 单次票(最常见)
| 角色 | 价格 | 备注 |
|---|---|---|
| 业户本人 | ¥20-50 / 次 | 折扣价 |
| 业户家属(同户人)| ¥20-50 / 次 | 折扣价 |
| 业户访客 | ¥30-100 / 次 | 全价 |
| 非业户(社会公众)| ¥50-150 / 次 | 部分小区不对外开放 |
### 月卡 / 季卡 / 年卡
| 类型 | 价格 | 适用 |
|---|---|---|
| 月卡 | ¥200-500 | 暑假期间高频用户 |
| 季卡 | ¥500-1200 | 整夏使用 |
| 年卡 | ¥1500-3000 | 含冬季室内泳池 |
### 怎么买
1. 到泳池前台(注:**通常不是物业大厅**)
2. 报房号 + 人数 / 选择卡类型
3. 付钱(现金 / 微信扫码,POS 在泳池前台少见)
4. 拿到**纸质票** / **入场卡**
> [!success] 简单粗暴
> 全过程 1 分钟内完成,业户进泳池游泳。
## 业务人员视角
### 操作差异(对比 IC 卡)
| 维度 | IC 卡 | 泳票 |
|---|---|---|
| 频率 | 偶尔(丢卡时)| **每天高频**,夏季尤甚 |
| 单价 | ¥30-50 | ¥20(单次)~ ¥3000(年卡)|
| 凭证 | 实物 IC 卡 | 纸质票 + 入场记录 |
| 退票需求 | 几乎没有 | **较常见**(下雨、孩子拉肚子等)|
| 现金占比 | 60-70% | **80-90%**(年龄段差异) |
### 业务人员压力
> [!warning] 夏季高峰期注意
> 周末下午 2-5 点排队最多。建议:
> - 提前打开 Filament 后台,免去频繁登录
> - 月卡 / 季卡固定收费项目,避免每次手动改单价
> - 现金抽屉里准备好 ¥1 / ¥5 / ¥10 / ¥20 零钱
> - **现场不要给二维码扫错收款码** —— 用商户分类码,款项直进物业账户
### 月卡 / 季卡的"二维码核验"
物业泳池通常会给业户**绑定刷卡入场**或**二维码核验**:
```
方案 A:绑定门禁 IC 卡
└── 买月卡时同时把权限写入业户的 IC 卡
└── 业户用 IC 卡刷卡入场(系统识别卡是否在有效期)
方案 B:小程序生成二维码
└── 业户买月卡后,小程序端生成动态二维码
└── 泳池入口扫码核验
```
**两种方案系统层面都不涉及一次性收费模块** —— 只在购买时建一笔订单。后续核验属于设备/小程序模块。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 泳池前台
participant 一次性收费
participant 现金抽屉
业户->>泳池前台: 报房号 + 买票
泳池前台->>一次性收费: 选项目 + 数量 + 现金
一次性收费->>一次性收费: 一气呵成建三件套
一次性收费-->>泳池前台: 完成
泳池前台->>现金抽屉: 收钱 + 找零
泳池前台->>业户: 给纸质票 + 收据
```
## 常见问题
> [!question] 业户买完月卡发现孩子要补习不能游了,能退吗?
> 这取决于物业政策。技术上走 [[场景-已收款作废]] 流程可作废 + 退现金。**建议物业制定明确规则**(比如"购买后 7 天内无使用记录可全额退、超过 7 天按比例")。
> [!question] 业户买单次票当天没去游成,能改天用吗?
> 物理纸质票的话,**纸票本身没限定日期**(取决于物业政策)。系统里那笔订单不需要改 —— 业户拿着原票来即可。如果是入场卡 / 二维码,要看核验系统怎么算。
> [!question] 泳池前台和物业大厅前台是同一个系统吗?
> **是的**。同一个 Filament 后台,只是不同员工登录。所有交易归到同一个数据库。
> [!question] 高峰期能批量录入吗?
> 当前每笔订单需要逐个录入。如果业户买 10 张单次票一次性付款,职员**填一笔 "数量=10"** 即可(不用录 10 次)。
## 相关概念
- [[概念-A流与B流]]
- [[概念-CollectionOrder与Receipt]]
- [[场景-A流-前台购买IC卡]] — 标准 A 流模板
## 异常分支
- 录错张数 → [[场景-已收款作废]]
- 业户当场反悔 → [[场景-已收款作废]]
- 业户多扫了款 → [[场景-已收款作废]] + 微信退款

View File

@@ -0,0 +1,146 @@
---
title: prop-acc · 场景 - A 流 - 前台购买装修出入证
aliases:
- 场景 - A 流 - 前台购买装修出入证
- 场景-A流-前台购买装修出入证
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- A流
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:前台购买装修出入证
业户装修期间需要发给工人的临时出入凭证。和 [[场景-A流-前台购买IC卡|IC 卡场景]]非常类似,但有几个**装修专属特点**。
## 典型情境
> [!example] 真实情境
> 王先生买了新房要装修,装修公司带 8 个工人。装修队进场要刷卡进小区门禁,他需要去物业办 8 张装修出入证。
## 业户视角
### 第 1 步:准备材料
| 材料 | 用途 |
|---|---|
| 业主身份证 / 房产证 | 证明是您的房 |
| **装修施工合同** | 物业要存档登记 |
| **装修方案 / 报建表** | 部分高端物业要求 |
| 工人身份证(全部)| 出入证上要写工人姓名 |
### 第 2 步:到前台
"我家要装修,需要办 8 张工人出入证。"
### 第 3 步:核对工人信息
职员会**逐人录入工人信息**,这一步比 IC 卡慢。每张装修证关联具体工人姓名 + 身份证号。
### 第 4 步:付款 + 拿证
- 单张装修证常见 ¥10-50(各物业政策不同)
- 8 张合计可能 ¥80-400
- 现金 / 微信 / POS 均可
- 当场拿到 8 张实体出入证
> [!info] 装修押金?
> 大部分物业除了收装修证费用,还会同时收**装修押金**(¥5000-10000),押金属于保证金模块,不是一次性收费。两者一般同时办,但走不同流程。详见保证金模块文档(待补)。
## 业务人员视角
### 操作差异(对比 IC 卡)
| 维度 | IC 卡 | 装修出入证 |
|---|---|---|
| 数量 | 通常 1 张 | 经常 5-20 张 |
| 单价 | ¥30-50 | ¥10-50 |
| 必填字段 | 业户 + 房号 | 业户 + 房号 + **每个工人身份信息** |
| 关联其他模块 | ❌ | 通常同时办**装修押金** |
| 有效期 | 长期 | **装修期内**(常见 3-6 个月) |
| 实物 | IC 卡片 | 出入证(卡片或臂章) |
### 建议操作流程
```
1. 装修合同存档(纸质或扫描进系统)
2. 收装修押金(走保证金模块的 DepositAction)
├── 业户付 ¥5000
└── 系统建 DepositAccount + 收据
3. 收装修证费用(本场景)
├── 8 张 × ¥30 = ¥240
├── Filament 后台 → 一次性收费 → 新建
├── 数量填 8
├── 备注栏列出 8 个工人姓名 + 身份证
└── 提交
4. 制证 + 发证
```
### Filament 录入
| 字段 | 填什么 |
|---|---|
| 业户 | 通过房号搜业户 |
| 收费项目 | "装修出入证" |
| 数量 | 8 |
| 金额 | 自动计算 ¥240(可手动调)|
| 支付方式 | 微信 / 现金 / POS |
| 备注 | 列出工人姓名 + 身份证号 + 装修期 |
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 前台
participant 保证金模块
participant 一次性收费模块
业户->>前台: 我要装修,办手续
前台->>前台: 核对身份 + 合同存档
Note over 业户,保证金模块: 第 1 笔:装修押金
前台->>保证金模块: DepositAction (¥5000)
保证金模块-->>业户: 押金收据
Note over 业户,一次性收费模块: 第 2 笔:装修出入证
前台->>一次性收费模块: CreateAdHocEventAction (8张 × ¥30)
一次性收费模块-->>业户: 收据 + 8 张出入证
```
## 常见问题
> [!question] 业户想加几个工人怎么办?
> **新开一笔订单**录入新工人,不影响原订单。系统里就是两笔独立 AdHocEvent。
> [!question] 装修期延长,出入证可以续期吗?
> 当前系统**不管出入证的有效期**,这是物业内部管理事项。如需续期,通常的做法是**新开一笔订单**重新收费。
> [!question] 装修中工人退出怎么办?
> 出入证收回作废即可,**不会退费**(本来就是临时性消耗品)。系统里那笔订单**不需要作废**(产品已售出)。
> [!question] 装修结束,押金怎么退?
> 走保证金模块的 `RefundFromDepositAccountAction`,生成红字凭证。详见保证金模块退款场景(待补)。
> [!question] 业户在小程序上能办装修证吗?
> 技术上 B 流支持,但实际很少这么做 —— 因为要核对工人身份和装修合同,前台**当面办更稳妥**。
## 相关概念
- [[概念-A流与B流]]
- [[概念-CollectionOrder与Receipt]]
- [[场景-A流-前台购买IC卡]] — 标准 A 流模板
- [[场景-A流-装修公司批量采购出入证]] — 装修公司角度(承包多个项目)
## 异常分支
- 录错金额 / 工人数 → [[场景-已收款作废]]
- 业户付完反悔 → [[场景-已收款作废]]

View File

@@ -0,0 +1,150 @@
---
title: prop-acc · 场景 - A 流 - 前台办理充电桩电费充值
aliases:
- 场景 - A 流 - 前台办理充电桩电费充值
- 场景-A流-前台办理充电桩电费充值
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- A流
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:前台办理充电桩电费充值
电动车业主**预付式电费充值**。充值后电费从余额扣减。
> [!warning] 这其实更适合预存款模块
> 严格说,这种"预存后逐次抵扣"的场景应该走 **[[预存款]]**(`PrepaidAccount` + `ConsumeAction`),而不是一次性收费。本场景描述的是**一次性买"电费券" / "充值码"** 的简化模式 —— 适合不需要逐次扣减的小区。
## 两种实现方式
### 方式 A:走一次性收费(简化,本场景)
业户付钱买**预付电费充值码**(类似话费充值卡),自己输入到充电桩。
- **适合**:充电桩支持充值码兑换
- **优点**:简单,后台只记一笔交易
- **缺点**:业户余额不在物业系统里,核对靠物理充值码
### 方式 B:走预存款模块(规范)
业户预存到物业开的"预付电费账户"(`PrepaidAccount`),用电时由集抄系统调用 `ConsumeAction` 自动扣减。
- **适合**:充电桩有联网,能实时上报用电量
- **优点**:业户余额清楚,系统自动扣减,可生成月度账单
- **缺点**:需要充电桩硬件支持联网
> [!info] 本文档继续讲方式 A
> 方式 B 详见预存款模块的"业户充值场景"(待补)。
## 典型情境
> [!example] 真实情境
> 张先生家有一辆电动车,小区充电桩需要预付费才能用。他来物业前台想充 ¥200。
## 业户视角
### 第 1 步:到前台
"我要给充电桩充 ¥200。"
### 第 2 步:付款
- 现金 / 微信 / POS
- 物业职员录入金额、提交
### 第 3 步:拿到充值码
- 职员给您**一张小票** 或 **微信发您一串充值码**
- 您在充电桩上输入,余额到账
> [!tip] 也可以打到 IC 卡
> 如果您的门禁 IC 卡支持电费(常见高档小区),职员可以**直接把 ¥200 余额写入您的 IC 卡**,不用记充值码。
## 业务人员视角
### Filament 录入(与 IC 卡几乎一样)
| 字段 | 填什么 |
|---|---|
| 业户 | 通过房号搜业户 |
| 收费项目 | "充电桩电费充值" |
| 数量 | 1(几张充值卡) |
| 金额 | 业户要充多少 |
| 支付方式 | 现金 / 微信 / POS |
| 备注 | 充值码 / 卡号(便于核对)|
### 与其他充值的对比
| 充值类型 | 模块 | 单价规则 |
|---|---|---|
| 充电桩(本场景)| 一次性收费 | 业户付多少充多少(无固定单价)|
| IC 卡 | 一次性收费 | 固定单价 ¥30-50 / 张 |
| 装修出入证 | 一次性收费 | 固定单价 ¥10-50 / 张 |
| 预存物业费 | 预存款模块 | 业户付多少存多少 |
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 前台
participant 一次性收费
participant 充电桩
业户->>前台: 充 ¥200 电费
前台->>一次性收费: 录入金额 + 提交
一次性收费-->>前台: 完成 + 充值码
前台->>业户: 给充值码 + 收据
业户->>充电桩: 输入充值码
充电桩-->>业户: 余额 ¥200
```
## 常见问题
> [!question] 充值码丢了能补办吗?
> 不能。充值码本质是"一次性使用"的密码。建议立刻在充电桩输入,不要保留。
> [!question] 业户充错金额(想充 ¥200 充成 ¥2000)能改吗?
> **作废重做**:走 [[场景-已收款作废]] 退还 ¥2000,重新录 ¥200。**前提是充值码还没用**。
> [!question] 业户余额没用完想退怎么办?
> 取决于物业政策。技术上**这条订单不能"部分退"**(订单是原子的)。变通方案:
> - 联系业户,作废原订单(退全款 ¥200)
> - 业户重新付实际使用金额(比如已用 ¥50 → 重新录一笔 ¥50)
> [!question] 充值码能给别人用吗?
> 系统不限制 —— 充值码是"凭码兑换",**谁拿到谁能用**。业务上各物业政策不同。
## 何时换成预存款模块?
> [!tip] 升级到方式 B 的信号
> 如果你们小区出现以下情况,该考虑切换到预存款模块:
> - 业户经常问"我还剩多少钱"
> - 财务想月底对账"全小区欠多少预付费"
> - 充电桩硬件升级了能联网
切换路径:
1. 业户开 PrepaidAccount(预存款账户)
2. 充值走 `DepositAction`(预付款模块)
3. 用电由集抄系统自动 `ConsumeAction` 扣减
## 相关概念
- [[概念-A流与B流]]
- [[概念-CollectionOrder与Receipt]]
- [[场景-A流-前台购买IC卡]] — 模板
- 预存款模块文档(待补) — 方式 B 的实现
## 异常分支
- 充错金额 → [[场景-已收款作废]] + 重做
- 充值码丢失 → 不可补办,业务沟通退款

View File

@@ -0,0 +1,154 @@
---
title: prop-acc · 场景 - A 流 - 装修公司批量采购出入证
aliases:
- 场景 - A 流 - 装修公司批量采购出入证
- 场景-A流-装修公司批量采购出入证
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- A流
audience:
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:装修公司批量采购出入证
**与个人业户买装修证不同**:大型装修公司同时承包小区里几十户装修,每户都要发出入证 —— 一次买 50-200 张的场景。
> [!info] 主要给业务人员看
> 这个场景对业户(装修公司联系人)而言是"批量买 + 一笔结清";对业务人员是"录入快、对账难"。
## 典型情境
> [!example] 真实情境
> 鸿基装修公司在小区里承包 12 户精装修业务,共需要 60 张出入证。公司财务下午到物业,要一次性办完 60 张 + 一张发票。
## 业户(装修公司联系人)视角
### 您要准备什么
| 材料 | 数量 |
|---|---|
| 公司营业执照复印件 | 1 份 |
| 法人 / 经办人身份证 | 1 份 |
| **每户的装修合同**(原件 + 复印件)| 12 份 |
| 60 个工人的身份证复印件 | 60 份 |
| **可开发票的公司抬头 / 税号** | 用于开发票 |
### 流程
1. 到物业前台,出示材料
2. 物业核对身份和合同
3. 物业算总价:60 张 × ¥30 = ¥1800
4. 您付款(**通常公司账户转账或 POS 公司卡**)
5. 拿到 60 张装修证 + 发票(发票流程独立)
6. 把 60 张证按工地分发给工头
## 业务人员视角
### 关键策略:**一笔订单 vs 多笔订单**?
> [!warning] 重要决策
> 60 张装修证,**应该录成 1 笔订单(数量=60),还是 12 笔订单(每户一笔)**?
| 录法 | 优点 | 缺点 |
|---|---|---|
| **1 笔订单**(数量=60) | 操作快、收据 1 张 | 业户对账难,出问题作废只能整体作废 60 张 |
| **12 笔订单**(每户 1 笔) | 业户能按户对账,作废粒度细 | 录入慢、收据多张 |
| **15-30 笔混合** | 灵活,按楼栋分 | 取决于业务习惯 |
**推荐**:**按户分笔**(12 笔订单)。原因:
- 每户的装修合同号、工人名册都不一样,对账时能精确到户
- 后续如果某户停工要作废,只影响那一户的几张证
- 发票可以多张合并出(发票流程不绑定订单数量)
### Filament 录入(12 笔订单的版本)
```
1. 收公司财务的总金额 ¥1800
2. 对照装修合同清单,按户录入 12 笔:
├── 户 12-3-501,5 张装修证 ¥150
├── 户 12-3-502,4 张装修证 ¥120
├── ...
3. 12 笔订单的支付方式都填"公司转账"
4. 备注栏写"鸿基装修公司批量采购,合同号 XX"
5. 检查总金额 = ¥1800
6. 出 12 张收据 + 1 张发票(发票合并)
```
### 一笔订单的版本(快速版)
```
1. Filament 后台 → 一次性收费 → 新建
2. 业户:不绑定具体房号,填"鸿基装修公司"
3. 收费项目:装修出入证
4. 数量:60
5. 金额:1800
6. 支付方式:公司转账
7. 备注:"60 张,涉及房号:12-3-501, 12-3-502, ...(12 户)"
8. 提交
```
> [!warning] 一笔录入的副作用
> 这笔订单的 `community_user_profile_id` 不一定挂得上(装修公司不是常规业户)。
> 如果系统里没有装修公司的 `CommunityUserProfile`,**得先建一个"客户档案"再下订单**。
## 系统流程
```mermaid
sequenceDiagram
participant 装修公司
participant 前台
participant 系统
participant 财务
装修公司->>前台: 60 张装修证 + 12 户合同
前台->>前台: 核对合同 + 工人名册
Note over 前台,系统: 推荐:按户分 12 笔
loop 每户
前台->>系统: 录入一笔 AdHocEvent
系统-->>前台: 收据 1 张
end
装修公司->>前台: 公司账户转账 ¥1800
前台->>系统: 12 笔订单状态 Completed
前台->>财务: 走发票合并流程
财务-->>装修公司: 发票 1 张(¥1800)
```
## 常见问题
> [!question] 公司转账有时差,前台先发证还是先收款?
> 业界惯例是**先入账后发证**。技术上 12 笔订单可以**先建 Pending 状态**(B 流),等转账到账后再统一翻 Completed。
>
> 当前 A 流是即收即付,只能等款到账后录入。如果转账走 1-2 天,可以折中:
> 1. 当天先录 Pending(用 B 流的 `CreatePendingAdHocEventAction`)
> 2. 到账日再批量翻 Completed
> [!question] 业户要求开**一张大发票** 还是 **12 张小发票**?
> 发票流程独立于订单,系统不强制对应关系。多数公司要一张大发票(便于报销),物业方按业户需求开即可。
> [!question] 60 张证录 12 笔太慢了,有批量录入吗?
> 当前 Filament 后台**没有批量录入入口**。如果业务上批量场景很多,可以考虑加一个"批量下单" Filament Action(类似 ImportMeterReadingsAction 的导入模式)。**等业务方反馈再做**。
> [!question] 装修公司中途停工(只用了 30 张证)能退一半吗?
> 技术上每笔订单可以**单独作废**(详见 [[场景-已收款作废]])。30 张证对应作废 6 笔订单(假设按户分笔且每户 5 张),保留另外 6 户的 30 张。
>
> 如果是 1 笔大订单,**只能整体作废 60 张**,粒度不够。这就是推荐"按户分笔"的关键原因之一。
## 相关概念
- [[概念-A流与B流]]
- [[概念-CollectionOrder与Receipt]]
- [[场景-A流-前台购买装修出入证]] — 单户场景
## 异常分支
- 某户中途停工 → [[场景-已收款作废]] 作废对应那几笔
- 录入金额错误 → [[场景-已收款作废]] 重做

View File

@@ -0,0 +1,139 @@
---
title: prop-acc · 场景 - B 流 - 小程序下单 + 支付宝
aliases:
- 场景 - B 流 - 小程序下单 + 支付宝
- 场景-B流-小程序下单+支付宝
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- B流
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:小程序下单 + 支付宝
业户在小程序内下单,**用支付宝(而非微信)** 完成支付。
> [!info] 几乎与微信流程一致
> 这个场景与 [[场景-B流-小程序下单+微信支付]] 99% 相同。本文档只描述**两种支付渠道的差异**。
## 业户视角
### 与微信支付流程的区别
| 维度 | 微信支付 | 支付宝 |
|---|---|---|
| 入口 | 微信小程序内拉起微信支付 | 微信小程序中**通过 H5 跳转支付宝**(或扫支付宝二维码)|
| 跳转体验 | 流畅(同一应用内) | 略多 1-2 步(跨应用)|
| 适用业户 | 偏年轻用户、华南地区 | 全国通用、商务用户更习惯 |
| 商户费率 | 0.2-0.6% | 0.55% |
| 回调速度 | 秒级 | 秒级(偶尔几十秒) |
### 业户实际操作
1. 在小程序选项目下单(完全相同)
2. 提交后选择"支付宝支付"
3. **微信小程序提示**:"即将跳转到支付宝完成支付"
4. 点确认 → 自动跳转支付宝 App
5. 输入支付宝密码 / 指纹完成支付
6. **自动跳回小程序**,显示支付成功
> [!success] 完成
> 跨应用跳转 → 回跳整个过程通常 < 10 秒。
## 业务人员视角
### 与微信流程的唯一区别:对账
> [!warning] 月底对账要分账户
> - 微信支付的款进**物业微信商户号**
> - 支付宝的款进**物业支付宝商户号**
>
> 两个商户号一般绑定**两个不同的银行账户**。月底对账时,要分别拉两边的流水。
在 Filament 后台,`CollectionOrder.payment_channel` 字段区分了不同支付方式:
```
collection_orders
├── payment_channel: "微信支付" → 对账走微信流水
└── payment_channel: "支付宝" → 对账走支付宝流水
```
财务月底查询:
```sql
-- 微信渠道
SELECT SUM(actual_amount) FROM acc_collection_orders
WHERE collection_completed_at BETWEEN '2026-05-01' AND '2026-05-31'
AND payment_method LIKE '%微信%';
-- 支付宝渠道
SELECT SUM(actual_amount) FROM acc_collection_orders
WHERE collection_completed_at BETWEEN '2026-05-01' AND '2026-05-31'
AND payment_method LIKE '%支付宝%';
```
详见 [[场景-审计-月底现金对账]]。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 小程序
participant 系统
participant 支付宝
业户->>小程序: 下单,选支付宝
小程序->>系统: POST /api/ad-hoc-events
系统-->>小程序: 订单号 CO-xxx + 支付宝拉起参数
Note over 小程序,支付宝: 跨应用跳转
小程序->>支付宝: 拉起支付(H5/SDK)
业户->>支付宝: 密码 / 指纹
支付宝->>系统: POST /webhook/alipay
系统->>系统: MarkAdHocEventPaidAction (payment_channel='支付宝')
系统->>系统: 同微信流程,翻 Completed + 生成 Receipt
系统-->>小程序: 推通知
支付宝-->>业户: 跳回小程序
小程序-->>业户: 显示已付款
```
## 常见问题
> [!question] 业户没装支付宝怎么办?
> 微信小程序内拉起支付宝**要求业户手机里装了支付宝 App**。没装的话会失败。变通方案:让业户选微信支付,或换 [[场景-跨渠道补缴|跨渠道到前台]] 现金/POS。
> [!question] 支付宝跳转回小程序失败怎么办?
> 这种情况钱已经扣了但小程序没显示成功。**支付宝有"支付成功通知"** 推送给业户,业户在支付宝里能看到。系统的支付宝回调一般 30 秒内能到,**让业户等等**,不要重复支付。
> [!question] 为什么不直接做支付宝小程序?
> 单独做一个支付宝小程序意味着双套代码,运营也要双倍发文章。**等业户群超过 30% 用支付宝时再考虑**。当前**微信小程序 + 跳转支付宝**是最划算的方案。
> [!question] 业务人员能在后台手动加一笔"支付宝退款"吗?
> 当前不在 UI 暴露(同微信)。退款流程:
> 1. 业户申诉
> 2. 业务人员去支付宝商户后台手动发起退款(支付宝平台操作)
> 3. 在 Filament 后台对应订单走 [[场景-已收款作废]] 标记
>
> 等支付网关 webhook 上线后,可以自动化。
## 相关概念
- [[概念-A流与B流]]
- [[概念-CollectionOrder与Receipt]] — `payment_method` 字段区分渠道
- [[场景-B流-小程序下单+微信支付]] — 标准 B 流
- [[场景-审计-月底现金对账]] — 多渠道对账
## 异常分支
- 支付完成但小程序卡死 → 系统会按 webhook 数据为准,后台可见已收款
- 想取消未付订单 → 场景-取消-业户改主意主动撤单

View File

@@ -0,0 +1,132 @@
---
title: prop-acc · 场景 - B 流 - 小程序下单 + 微信支付
aliases:
- 场景 - B 流 - 小程序下单 + 微信支付
- 场景-B流-小程序下单+微信支付
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- B流
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:小程序下单 + 微信支付
线上 B 流的标准路径。**业户自助、24h 可办、无需到柜台**。
> [!warning] 当前阶段
> 后端数据模型 + Action 已就绪(2026-05-21 落地)。**小程序 API + 支付网关回调 webhook 还在开发**。本场景描述的是上线后的完整体验。
## 典型情境
> [!example] 真实情境
> 小李,32 岁,周三晚上 9 点在家想给老婆买张游泳卡。物业前台早下班了,但他打开物业小程序,5 分钟搞定。
## 业户视角(您要做什么)
### 第 1 步:打开小程序
进入"我家 → 一次性收费"
### 第 2 步:选项目
页面上列出您能买的项目(IC 卡 / 装修证 / 泳票 / 充电桩电费 / ...)。点击"游泳卡"。
### 第 3 步:确认订单
- 项目:游泳卡(月卡)
- 单价:¥200
- 数量:1(可调)
- 金额:¥200
> [!info] 系统里发生了什么
> 您点"确认下单"后,系统**冻结当前价格**(以后涨价不影响您这单),给您一个订单号。
>
> 订单状态此刻:`Pending`(待付款),**30 分钟内有效**。
### 第 4 步:微信支付
跳转到微信支付页面,密码 / 指纹 / 扫脸付款。
### 第 5 步:小程序通知
支付成功后,小程序弹通知:**"已付款,可至前台领取游泳卡"** + 收据 PDF 自动生成,在"我的订单"里可下载。
> [!success] 完成
> 系统状态此刻:订单 `Completed`,收据 `Issued`,所有记录归档。
## 业务人员视角
> [!tip] 前台几乎不用操作
> 业户线上完成全部流程,**前台只需在业户来取货时核对订单号**:
>
> 1. 打开 Filament 后台 → 一次性收费
> 2. 搜业户的订单号(CO-xxx)
> 3. 确认状态是 Completed
> 4. 把游泳卡 / 物理凭证交给业户
不需要再录任何东西 —— **业户线上做完了所有数据录入**
## 系统流程(技术视角)
```mermaid
sequenceDiagram
participant 业户
participant 小程序
participant 系统
participant 微信支付
participant 监听器
业户->>小程序: 选游泳卡、确认下单
小程序->>系统: POST /api/ad-hoc-events
系统->>系统: CreatePendingAdHocEventAction
系统->>系统: 1. 建 AdHocEvent (Pending)
系统->>系统: 2. 建 CollectionOrder (Pending, expires_at=now+30min)
系统-->>小程序: 返回订单号 CO-xxx + 支付参数
小程序->>微信支付: 拉起支付
业户->>微信支付: 输入密码 / 指纹
微信支付->>系统: POST /webhook/wechat-pay
系统->>系统: MarkAdHocEventPaidAction
系统->>系统: 1. 补支付字段到 CO
系统->>系统: 2. 翻 CO → Completed
系统->>系统: 3. 翻 AdHocEvent → Completed
系统->>系统: 4. 清 expires_at
系统->>监听器: 触发 CollectionOrderCompleted
监听器->>系统: 建 Receipt + ReceiptItem
系统-->>小程序: 推通知 + 收据 PDF
小程序-->>业户: 弹"已付款,可来取货"
```
## 常见问题
> [!question] 我下完单忘记付怎么办?
> 30 分钟内没付,订单**自动作废**,价格也释放。您可以重新下单,**但价格按当前价**(以防您预定旧价、等到打折涨价才付)。详见 [[场景-超时未付自动作废]]。
> [!question] 付了钱小程序没显示成功怎么办?
> 微信支付有可能延迟回调(几秒到几分钟)。**别重复支付**!等几分钟再看小程序"我的订单"。若 10 分钟还没更新,联系物业,他们能后台手动核实。
> [!question] 我可以让我儿子帮我下单吗?
> 完全可以,而且您可以**不用儿子付钱** —— 让儿子帮您下完单,您拿订单号到前台付现金即可。详见 [[场景-跨渠道补缴]]。
> [!question] 想换支付方式?微信换支付宝?
> 同一笔订单不能换。如果还没付,在小程序"我的订单"里**撤单**,重新下一单选支付宝。
## 异常分支
- 想取消未付订单 → 场景-取消-业户改主意主动撤单(待补)
- 超时没付了 → [[场景-超时未付自动作废]]
- 跨渠道支付 → [[场景-跨渠道补缴]]
- 付了款发现订单数据错 → [[场景-已收款作废]]
## 相关概念
- [[概念-A流与B流]] — 为什么 B 流要"下单 + 支付"两步
- [[概念-CollectionOrder与Receipt]] — 订单和收据生成时机
- [[概念-AdHocEvent状态机]] — Pending → Completed 流转

View File

@@ -0,0 +1,204 @@
---
title: prop-acc · 场景 - 收据 - 小程序自助下载 PDF
aliases:
- 场景 - 收据 - 小程序自助下载 PDF
- 场景-收据-小程序自助下载PDF
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 收据凭证
audience:
- 业户
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:小程序自助下载 PDF 收据
业户在小程序里**自己下载电子收据**。无需联系物业,24h 自助。
> [!success] 推荐路径
> 这是最方便的收据获取方式。任何时候、任何手机、任何业户都能自助操作。
## 典型情境
> [!example] 真实情境
> 周三晚上 10 点,陈太太需要把上个月在物业买充电桩电费的收据 PDF 发给公司财务报销。她不想等明天物业上班,**直接在小程序里下载**。
## 业户视角
### 第 1 步:打开小程序
进入"我家 → 我的订单"
### 第 2 步:找到目标订单
在"已完成"列表里找:
```
我的订单 → 已完成
├── 游泳卡 × 2 ¥40 2026-05-20
│ 订单号 CO-20260520-XXX
│ [查看详情] [📥下载收据]
├── 充电桩电费 ¥200 2026-05-15 ← 这一笔
│ 订单号 CO-20260515-YYY
│ [查看详情] [📥下载收据]
└── ...
```
### 第 3 步:点"下载收据"
```
正在生成 PDF...
✅ 收据已生成
[在微信中打开] [保存到手机]
```
### 第 4 步:转发给财务
- **转发到微信好友**(公司财务)
- **保存到手机相册**(图片格式更通用)
- **保存到微信文件**(后续打开还能用)
- **打印** —— 微信里支持调用蓝牙打印机
> [!success] 完成
> 全程 1 分钟,无需任何外部协助。
## 您能下载的所有收据
> [!info] 全部历史
> 小程序"已完成"列表展示**该业户的所有历史订单**,无时间限制。理论上 5 年前的订单还能下载收据。
如果列表太多,可以筛选:
- 按时间(月 / 季 / 年)
- 按项目类型(IC 卡 / 装修证 / 泳票 / 充电桩)
- 按金额范围
## PDF 收据长什么样?
```
┌─────────────────────────────────────┐
│ 鸿基物业管理有限公司 │
│ 收 据 │
│ │
│ 收据号:R-20260515-XXX │
│ 日期:2026-05-15 14:30 │
│ ───────────────────────────────── │
│ 收款方:鸿基物业管理有限公司 │
│ 付款方:陈XX(房号 12-3-501) │
│ ───────────────────────────────── │
│ 项目 数量 金额 │
│ ───────────────────────────────── │
│ 充电桩电费充值 1 ¥200.00 │
│ ───────────────────────────────── │
│ 合计 ¥200.00 │
│ │
│ 支付方式:微信支付 │
│ 支付时间:2026-05-15 14:30:25 │
│ 订单号:CO-20260515-YYY │
│ │
│ [电子公章] │
└─────────────────────────────────────┘
```
> [!info] 关于电子公章
> PDF 上的电子公章是**预先嵌入模板**的物业印章图像。**与纸质收据法律效力相同**,但部分公司财务可能要求另开纸质章 —— 取决于公司政策。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 小程序
participant 系统
participant PDF生成器
业户->>小程序: 点击"下载收据"
小程序->>系统: GET /receipts/{id}/pdf
系统->>系统: 查 Receipt 数据
alt 收据状态正常
系统->>PDF生成器: 渲染 PDF
PDF生成器-->>系统: PDF 流
系统-->>小程序: 返回 PDF
小程序-->>业户: 显示"在微信中打开"
else 收据已作废
系统-->>小程序: 返回 PDF (含"已作废"水印)
小程序-->>业户: 显示带水印的 PDF
end
```
> [!info] 重新下载多少次都不影响
> 每次下载都是从数据库**实时生成 PDF**,不修改任何数据。下载 100 次和下载 1 次效果一样。
## 几种特殊情况
### 1. 收据已被作废
如果订单走过 [[场景-已收款作废]]:
- PDF 上会加 **"已作废" 红色水印**
- 业户依然能下载,作为"作废存档"
- **不能拿这张报销**(财务会看出水印)
### 2. 业户的微信换了手机
> [!question] 换手机后还能看到历史订单吗?
> **能**。订单关联**业户档案**(身份证 / 手机号),不绑定具体设备。新手机登录同一微信即可。
### 3. 业户换了手机号
> [!warning] 这种情况要联系物业
> 业户手机号变了 → **小程序登录账号变了**。需要物业**人工绑定新手机号**到原业户档案。否则新账号看不到旧订单。
### 4. 已经离开小区的前业户
> [!info] 还能下载
> 即使业户**搬走了**(`CommunityUserProfile.status = inactive`),只要数据没删,小程序里依然能看历史订单。**收据是历史凭证,不应该因离开而消失**。
## 常见问题
> [!question] 我能批量下载多张收据吗?
> 当前**一次只能下一张**。如果你要把一整年的收据打包下载(报销季),可以联系物业:
> - 物业可在 Filament 后台**导出某业户所有订单的 Excel**
> - 部分物业有"年度账单 PDF"功能(待补)
> [!question] PDF 文件多大?
> 通常 50-150 KB。微信里直接打开预览,不占流量。
> [!question] PDF 能修改吗?
> **不能**(无密码,但 PDF 本身不可编辑)。如果想加密 / 防伪,需要技术升级(挂 TODO)。
> [!question] 我的收据上信息错了(房号错)怎么办?
> 走 [[场景-已收款作废]] + 重做。重做时收据信息自动正确。**不能直接改 PDF**(也不能改数据库 Receipt 记录,违反审计完整性)。
> [!question] 收据上的电子公章会不会过期?
> 不会。电子公章是 PDF 图像,长期有效。
## 与现场打印的对照
| 维度 | 现场打印纸质收据 | 小程序下载 PDF(本场景) |
|---|---|---|
| 时机 | 仅前台营业时间 | **24h 自助** |
| 形态 | 纸质 + 物理章 | PDF + 电子章 |
| 适用 | 严格的财务 / 老人 | 大多数业户 |
| 物业人力 | 需要 | 完全不需要 |
| 报销 | 大多数公司认可 | 取决于公司政策 |
## 相关概念
- [[概念-CollectionOrder与Receipt]] — Receipt 表
- [[场景-A流-前台购买IC卡]] — 收据生成的原始流程
- [[场景-B流-小程序下单+微信支付]] — 收据生成的另一种触发
- [[场景-收据-现场打印纸质收据]] — 纸质替代方案
- [[场景-收据-重打丢失收据]] — 业务人员协助补打
## 异常分支
- 公司要纸质 → 走 [[场景-收据-现场打印纸质收据]]
- 信息错 → [[场景-已收款作废]] + 重做
- 想要发票 → 单独申请流程(超出本系统)

View File

@@ -0,0 +1,173 @@
---
title: prop-acc · 场景 - 收据 - 现场打印纸质收据
aliases:
- 场景 - 收据 - 现场打印纸质收据
- 场景-收据-现场打印纸质收据
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 收据凭证
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:现场打印纸质收据
业户买完东西要**纸质收据**(贴在公司报销单上、归档保存)。前台**当场用收据打印机出**。
## 典型情境
> [!example] 真实情境
> 王经理是某公司的行政,买了 5 张装修证(¥150)给装修工。要拿纸质收据回公司报销,**普通的微信电子收据不够**(财务要纸质,而且最好有印章)。
## 业户视角
### 您能拿到的纸质形态
| 类型 | 说明 | 是否能报销 |
|---|---|---|
| **打印机出小票** | 热敏纸 + 二维码 | 部分公司能,大公司通常不行 |
| **正规收据(三联单)** | 物业印章 + 手写 / 打印 | 大多数公司可报销 |
| **正规发票** | 国税局开具 | 全部公司可报销 |
| 微信电子收据 | 微信卡包 | 报销取决于公司政策 |
> [!info] 收据 ≠ 发票
> **收据**:证明"我付了钱给物业",有物业印章。
> **发票**:税务凭证,公司报销/抵扣进项税必需。
>
> 本系统**生成的是收据**,**不是发票**。要发票需要走独立的发票开具流程。
### 怎么要?
到前台:
> "麻烦给我打张纸质收据,要盖章的那种。"
物业职员会:
1. 在打印机上出一张**预打印收据**(已盖物业公章的纸质单据)
2. 在系统里同步把电子收据状态更新
3. 把纸质单交给您
或者更简单的:**让打印机直接出小票**(热敏纸,系统自动出)。
## 业务人员视角
### 出收据的几种方式
```
方式 A:热敏小票(最简单,1 秒出单)
├── Filament 后台订单详情 → 点"打印收据"
├── 热敏打印机直接出单
└── 适用:业户不在意是不是"正规收据"
方式 B:预打印套打收据(正规)
├── 物业有库存的"三联收据单"(纸质 + 物业印章)
├── 在 Filament 后台填套打数据,系统按收据格式打印到三联单上
├── 业户拿走第一联;前台留第二联;财务存第三联
└── 适用:业户要报销
方式 C:手写收据(应急)
├── 打印机故障 / 系统宕机
├── 手写三联单 + 盖章
└── 后续在系统里补录订单(注明手写编号)
```
### 推荐:**默认热敏小票,业户要"正规"再出预打印**
```
1. 业户付完款 → 自动出热敏小票
2. 业户走的时候问:"我能拿张能报销的吗?"
├── 是 → 出预打印收据
└── 否 → 完事
```
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 前台
participant Filament
participant 热敏打印机
participant 套打打印机
业户->>前台: 我要纸质收据
前台->>Filament: 订单详情 → "打印收据"
Filament->>热敏打印机: 默认走热敏
热敏打印机-->>前台: 出小票
前台->>业户: 给小票
Note over 业户: 业户:"我要能报销的"
前台->>Filament: 切换 "正规收据" 模式
Filament->>套打打印机: 按三联格式打印
套打打印机-->>前台: 三联收据
前台->>业户: 第一联(您拿) + 第二联(前台留)+ 第三联(财务存)
```
## 纸质收据应包含的字段
```
[物业 LOGO] [物业公章]
─────────────────────────────────
收 据
─────────────────────────────────
日期: 2026-05-25
收据号: R-20260525-001
收款方: 鸿基物业管理有限公司
付款方: 王XX(123-4-501)
项目 数量 金额
─────────────────────────────────
装修出入证 5 ¥150.00
─────────────────────────────────
合计 ¥150.00
支付方式: 现金 / 微信 / POS
[业务人员签字]
```
## 常见问题
> [!question] 热敏小票能不能盖章后报销?
> 取决于公司财务。**严格的公司只认正规收据/发票**,热敏小票会被退回。**保守做法**:给业户预打印收据。
> [!question] 套打打印机的"三联单"哪里有?
> 是物业预先采购的**带印章的空白三联单**(税务局有售卖或物业自行定制)。一般物业大厅 + 财务办公室都备一份。
> [!question] 印章会不会被滥用?
> 印章在**财务办公室管理员**手里,套打前先盖章再打印。每笔订单单独打 1 张。审计可对照系统订单数和领用印章次数。
> [!question] 业户要的是发票,不是收据怎么办?
> 让业户填**发票申请表**(公司抬头 + 税号),走税务开票流程。**这超出本系统范围**,通常需要财务部门用税控盘开。
> [!question] 后期能补打吗?
> 当然可以 —— 走 [[场景-收据-重打丢失收据]] 流程。
## 与其他收据场景的对照
| 收据需求 | 解决方案 |
|---|---|
| 当场要小票 | 本场景(热敏) |
| 当场要正规报销凭证 | 本场景(预打印套打) |
| 已经走了发现丢了 | [[场景-收据-重打丢失收据]] |
| 想自助下载电子版 | [[场景-收据-小程序自助下载PDF]] |
| 要正规发票(非收据) | 单独发票申请流程(超出本系统) |
## 相关概念
- [[概念-CollectionOrder与Receipt]] — Receipt 表 + ReceiptItem 关联
- [[场景-A流-前台购买IC卡]] — 标准买票流程
- [[场景-收据-重打丢失收据]] — 事后补打
- [[场景-收据-小程序自助下载PDF]] — 自助下载电子版
## 异常分支
- 打印机坏 → 手写三联 + 后续补录系统
- 业户要发票 → 单独流程

View File

@@ -0,0 +1,158 @@
---
title: prop-acc · 场景 - 收据 - 重打丢失收据
aliases:
- 场景 - 收据 - 重打丢失收据
- 场景-收据-重打丢失收据
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 收据凭证
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:重打丢失收据
业户**事后说收据丢了**,要求物业**补打或重发**。
> [!success] 系统已支持
> 后端已有 PDF 下载路由(`packages/prop-acc/routes/tenant.php`)。本场景描述前台 + 业户的两种重打路径。
## 典型情境
> [!example] 真实情境
> 张阿姨 3 个月前买了张 IC 卡 ¥30,需要找物业开发票报销公司。当时拿的是纸质收据,现在找不到了。来物业问:"能不能再打一份给我?"
## 业户视角
### 路径 A:业户自己在小程序下载
> [!tip] 推荐这个最方便
> 业户**自助操作**,不用麻烦前台。
1. 打开小程序 → 我家 → 我的订单
2. 在"已完成"列表找到那笔订单
3. 点订单详情 → 右上角 [下载收据]
4. PDF 自动下载,微信里可保存/分享
### 路径 B:让前台职员帮忙
业户不会用小程序时:
1. 到物业前台
2. "我 3 月份买的 IC 卡,收据丢了,能不能再给我一份?"
3. 报房号 / 大致日期 / 订单号(如果记得)
4. 职员搜系统、重新打印 / 发微信
## 业务人员视角
### 操作步骤
```
1. 打开 Filament 后台 → 一次性收费
2. 搜业户(按房号、日期、订单号)
3. 找到目标订单,点击进入详情
4. 找到关联的 Receipt
5. 点"下载 PDF"或"打印"按钮
6. 把 PDF 发到业户微信,或纸质打印当场给
```
### 重要:**不要新建一笔订单**
> [!warning] 关键
> 不要因为业户说"收据丢了"就**重新录一笔订单** —— 这会变成系统里**多了一笔不存在的交易**,财务多收一份钱。
>
> **正确做法**:用原订单**重新生成一份 PDF**。原 Receipt 不变(状态仍是 Issued),只是文档**被重新渲染**。
### 收据号会变吗?
**不会**。重打的收据**收据号、金额、日期** 全部和原始收据一样。这是"重打",不是"新开"。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 前台/小程序
participant 系统
participant PDF生成器
业户->>前台/小程序: 我要补一份收据
前台/小程序->>系统: GET /receipts/{id}/pdf
系统->>系统: 找到 Receipt 数据
系统->>PDF生成器: 渲染收据 PDF
PDF生成器-->>系统: PDF 二进制流
系统-->>前台/小程序: 返回 PDF
前台/小程序-->>业户: 下载/打印
```
> [!info] 系统里发生了什么
> - Receipt 表**没有任何写操作**(没改也没新增)
> - 只是用现存数据**重新生成 PDF**
> - 重打多少次都不会影响财务记录
## 几种特殊情况
### 业户的订单已被作废
如果业户找到的订单是 **Voided 状态**(走过作废流程):
```
Filament 后台显示:
├── Receipt 状态:Voided
├── PDF 上会有水印 / 字样:"已作废"
└── 业户拿这张是"作废凭证",不是有效收据
```
> [!warning] 业户可能会问"作废凭证能报销吗?"
> 不能(财务上这笔交易不存在了)。要重新报销,需要重新交易 + 拿新收据。
### 业户记不清是什么时候买的
```
1. 让业户回忆大致月份 / 商品类型
2. Filament 后台用业户 ID + 商品类型筛选
3. 列出该业户**所有历史订单**让业户认领
```
### 业户要发票而不是收据
> [!info] 收据 ≠ 发票
> - **收据**:系统自动生成,证明"我付了钱"
> - **发票**:税务凭证,需要走**开票流程**(国税局接口)
>
> 一次性收费当前**只生成收据**,不开发票。业户要发票需要走单独的发票申请流程(超出本系统范围)。
## 常见问题
> [!question] 业户说"前台给的收据上日期是错的"?
> 收据日期 = 订单的 `collection_completed_at`(收款完成时间)。如果业户付款时间和系统时间不一致(罕见),需要技术排查时间同步问题。**业务上可以加备注说明**。
> [!question] PDF 能不能加密 / 防伪?
> 当前未实现。如果有需要(防业户 PS),可以在 PDF 加二维码 + 收据号哈希,业户扫码到物业小程序验真。**等业务方反馈再做**。
> [!question] 重打的次数有限制吗?
> 没限制。每次重打都从数据库实时生成,**不影响其他数据**。
> [!question] 业户能查到所有历史收据吗?
> 在小程序"我的订单"里能看到**所有自己的订单**(无时间限制)。每笔订单都能重新下载收据。
> [!question] 业务人员能帮业户**删掉**一笔订单 / 收据吗?
> **不能**。Delete 入口在前台已经移除(详见 [[概念-AdHocEvent状态机]])。如果业户希望"这笔订单不存在",走 [[场景-已收款作废]] 即可 —— Receipt 状态翻 Voided 但记录仍在,方便审计。
## 相关概念
- [[概念-CollectionOrder与Receipt]] — Receipt 是只生成不可改的凭证
- [[场景-A流-前台购买IC卡]] — 原始收据生成
- [[场景-已收款作废]] — 作废后的收据状态
## 异常分支
- 收据上信息错(房号串错) → 走 [[场景-已收款作废]] + 重做
- 业户要的不是收据是发票 → 单独发票申请流程(超出本系统)

View File

@@ -0,0 +1,151 @@
---
title: prop-acc · 场景 - 已收款作废
aliases:
- 场景 - 已收款作废
- 场景-已收款作废
tags:
- 场景
- prop-acc
- 一次性收费
- 业务场景
- 取消退款
audience:
- 业户
- 业务人员
status: 已发布
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:已收款作废
业户**已经付了钱**,但因为各种原因(录错、反悔、退货)需要作废这笔交易。**走 VoidAction 路径**,系统级联废订单 + 收据,留完整审计。
## 典型情境
> [!example] 情境 1:职员录错金额
> 张阿姨买 IC 卡 ¥30,职员手滑录成 ¥300,业户付完发现不对。
>
> → 立刻作废 → 退还 ¥300 现金 → 重新录入正确金额 ¥30 → 业户重新付 ¥30。
> [!example] 情境 2:业户反悔
> 李先生买了张游泳卡 ¥200,出门走两步觉得不想要了。
>
> → 当场作废 → 退还 ¥200 现金。
> [!example] 情境 3:实物缺货
> 业户付了 IC 卡的钱,但当天工本卡库存为 0 制不了卡。
>
> → 作废订单 → 退还现金 → 等到货后业户再来。
## 业户视角
### 您看到什么
- 您付完钱后告诉职员要作废
- 职员当场操作,系统**几秒内完成**
- 现金当场退还(或微信原路退回)
- 您能收到**新的"作废收据"**或在小程序"我的订单"看到状态变 `已作废`
> [!success] 没有"二次扣款"风险
> 作废操作是**原子的**(整体成功或整体回滚)。不会出现"系统已退钱、但订单还显示已收款"的半成品状态。
## 业务人员视角
### 操作步骤
```
Filament 后台 → 一次性收费列表
├── 找到该订单(状态 Completed)
├── 点击行操作菜单
└── "作废"(红色危险按钮)
├── Modal 弹出
├── 必填:作废原因(详细文字,后续审计要看)
│ 例:"客户取消订单,现金已退还"
│ 例:"录入金额错误,客户付款后发现"
│ 例:"工本卡缺货,客户无法当场拿货"
├── 提交
└── 系统瞬间完成:
├── AdHocEvent → Voided
├── CollectionOrder → Failed
├── Receipt → Voided
└── meta 记 voided_at / voided_reason / voided_by
```
### 然后业务人员手动处理资金
> [!warning] 关键:**资金不会自动退**
> VoidAction 只更新数据库记录,**不会自动调用退款接口**。需要业务人员:
>
> - **现金支付**:从收银抽屉拿出对应金额还给业户
> - **微信支付**:在物业商户后台手动发起退款(微信会几小时内退到业户原账户)
> - **POS 刷卡**:在 POS 机上做"撤销"操作(只能当天)
>
> 如果业务方将来需要"作废 = 自动退款"的一体化,可以补 RefundAction。当前不做。
### 业务人员必须填的"作废原因"
> [!tip] 写清楚 = 自救
> 半年后审计来抽查,问"这笔为啥作废"。如果 voided_reason 只写"作废了" → 业务人员说不清。
>
> 推荐写法:
> - **谁要求作废**(客户主动 / 物业发现 / 系统异常)
> - **作废后资金处理**(已退现金 ¥X / 微信退款已发起 / 待退)
> - **是否同一笔后续会重做**(是 → 重新下单单号 / 否 → 完全取消)
## 系统流程
```mermaid
sequenceDiagram
participant 业务人员
participant Filament
participant 数据库
业务人员->>Filament: 选择已收款订单,点"作废"
Filament->>业务人员: 弹出 Modal,要求填作废原因
业务人员->>Filament: 提交(含原因)
Filament->>数据库: 开启事务
Filament->>数据库: 1. Receipt.void(reason) 翻 Voided
Filament->>数据库: 2. CollectionOrder.update(status=Failed, meta+voided_*)
Filament->>数据库: 3. AdHocEvent.update(status=Voided, meta+voided_*)
Filament->>数据库: 提交事务
Filament-->>业务人员: 作废成功通知
```
> [!info] 三表级联,一处失败全回滚
> Receipt 失败 → CollectionOrder 不动、AdHocEvent 不动。三张表要么全成功要么全回到原状,不会出现"事件作废了但收据还显示有效"的脏数据。
## 与 Pending 单作废的区别
| 维度 | Pending 单作废 | Completed 单作废(本场景) |
|---|---|---|
| 触发场景 | 业户撤单 / 超时 | 业户已付款后反悔 / 录错 |
| 是否级联废收据 | ❌ Pending 单没收据 | ✅ 收据翻 Voided |
| 资金 | 没收过,不用退 | **需手动退还**(系统不自动)|
| 操作复杂度 | 一键 | 一键 + 业务人员手动处理资金 |
## 常见问题
> [!question] 作废后还能"再恢复"成已收款吗?
> **不能**。Voided 是终态。要重做,**新建一单**即可(订单号会不同,审计独立)。
> [!question] 业务人员忘了写作废原因怎么办?
> Modal 表单**强制必填**,空着提交会被拒绝。
> [!question] 业户已经走了,我能事后作废吗?
> 技术上**可以**,但要**联系业户协调资金**(打电话叫人来拿钱、或微信转账)。原则上**当场处理最干净**。
> [!question] 这跟"退款"有什么区别?
> 作废 = "这笔交易不存在了,数据库标记废除"。退款 = "交易存在,但钱退回去了"。当前一次性收费**只做作废**,没有独立的退款流程。如果未来业务方需要"红字凭证 + 保留原单"的退款,会按保证金/预存款模块同款方式实现。
## 相关概念
- [[概念-AdHocEvent状态机]] — Completed → Voided 流转
- [[概念-CollectionOrder与Receipt]] — 三件套同步翻状态
- [[场景-A流-前台购买IC卡]] — 正向流程
- [[场景-B流-小程序下单+微信支付]] — 线上交易也可作废
## 待补场景
- 场景-取消-业户改主意主动撤单(Pending 单的撤单,业户在小程序操作)
- 场景-取消-录错金额作废重做(更详细的"作废+重做"组合流程)