vault backup: 2026-05-25 23:22:55
This commit is contained in:
195
prop-acc/scenarios/prepaid/consume-monthly-property-bill.md
Normal file
195
prop-acc/scenarios/prepaid/consume-monthly-property-bill.md
Normal file
@@ -0,0 +1,195 @@
|
||||
---
|
||||
title: prop-acc · prepaid · 场景 - 手动抵扣月度物业费
|
||||
aliases:
|
||||
- 抵扣物业费
|
||||
- 预存款抵账单
|
||||
- consume-monthly-property-bill
|
||||
- 场景-预存款抵月物业费
|
||||
tags:
|
||||
- 场景
|
||||
- prop-acc
|
||||
- 预存款
|
||||
- 消费
|
||||
audience:
|
||||
- 业户
|
||||
- 业务人员
|
||||
status: 已发布
|
||||
sub_feature: prepaid
|
||||
last_review: 2026-05-25
|
||||
code_version: 2026-05-22
|
||||
---
|
||||
|
||||
# 场景:手动抵扣月度物业费
|
||||
|
||||
预存款最高频操作 —— 月底物业费账单出来后,业务人员后台**手动触发** `ConsumeAction`,从业户的预存款余额扣对应金额、Bill 状态翻 Paid。**未来批量自动 job 落地后,这条路径变成"运维个例兜底"**(详见 [[auto-deduction-design]])。
|
||||
|
||||
## 典型情境
|
||||
|
||||
> [!example] 真实情境
|
||||
> 张阿姨的 12-3-501 房 5 月物业费账单 ¥800 已出账。张阿姨预存款账户余额 ¥4,200。物业财务王主管月初批量为 100+ 户业户做物业费抵扣,张阿姨是其中一户。
|
||||
|
||||
## 业户视角
|
||||
|
||||
### 您会感受到什么
|
||||
|
||||
- 5 月底账单出来后,几天内收到推送:
|
||||
> "您的 5 月物业费 ¥800 已自动从预存款扣减,余额 ¥3,400"
|
||||
- 收到收据:"物业费 ¥800(5 月)"
|
||||
- 小程序"我的预存款"显示新流水:`-800.00 抵扣 物业费(5月)`
|
||||
- 小程序"我的账单"显示该账单 ✅ 已付
|
||||
|
||||
### 您要做什么
|
||||
|
||||
什么都不用做。看看就行 ——
|
||||
|
||||
- 如果余额够,账单自动归零,无感
|
||||
- 如果余额不够,会收到"余额不足"提示,需要您手动充值或现金/微信付
|
||||
|
||||
> [!info] 与现金付的差异
|
||||
> 业户拿到的收据**长一样**(都是"物业费 ¥800"),只是结算来源不同。详见 [[consume-via-bill-collection-type]]。
|
||||
|
||||
## 业务人员视角
|
||||
|
||||
### 第 1 步:确认账单已生成
|
||||
|
||||
后台 → 账单(Bill)模块 → 5 月物业费账单批量 → 状态 Unpaid → 列表里有张阿姨的账单。
|
||||
|
||||
### 第 2 步:打开张阿姨的预存款账户
|
||||
|
||||
后台 → 预存款 → 账户列表 → 按业户姓名搜 → 找到 Active 账户(balance=4200)→ 进 `ViewPrepaidAccount`。
|
||||
|
||||
### 第 3 步:点击 `ConsumeAction`(标签"消费抵扣")
|
||||
|
||||
> [!warning] 按钮可见性
|
||||
> `ConsumeAction` 守护:`canOperate()`(Active only)+ `balance > 0` + Policy `->authorize('consume')`。Frozen / Closed / 零余额账户灰化。
|
||||
|
||||
Modal 表单:
|
||||
|
||||
| 字段 | 填什么 |
|
||||
|---|---|
|
||||
| **关联账单(Bill)** | 选业户的未付账单(下拉显示该业户 community 内 status=unpaid 的账单)|
|
||||
| **抵扣金额** | 自动带入账单金额(可改,部分抵扣场景)|
|
||||
| **备注** | 选填,如 "5 月物业费手动抵扣" |
|
||||
|
||||
### 第 4 步:提交
|
||||
|
||||
系统调 `ConsumeFromPrepaidAccountAction`,事务内:
|
||||
|
||||
1. 校验 `canOperate()`(Active only)
|
||||
2. 校验跨社区(Bill 与 Account 必须同 community)
|
||||
3. 校验余额(≥ 抵扣金额)
|
||||
4. 建 `CollectionOrder`(`type=Bill`,`actual=+800`,`meta.fund_source=prepaid`,`Completed`)
|
||||
5. 建 `CollectionOrderBill` 关联 CO 与 Bill
|
||||
6. 调 `PrepaidAccount::consume($bill, $amount)`:
|
||||
- 加 `PrepaidTransaction`(`type=consume`,`amount=800`,`balance_before=4200`,`balance_after=3400`,`related_bill_id=...`,关联 CO)
|
||||
- 更新 `balance=3400`
|
||||
7. 调 `Bill::recordPayment($amount)`:
|
||||
- 更新 `Bill.status=Paid`
|
||||
8. 触发 `CollectionOrderCompleted` → Listener 建 Receipt(走 Bill 渠道,文案"物业费 ¥800")
|
||||
|
||||
### 第 5 步:给收据 / 通知
|
||||
|
||||
后台找到新建 Receipt → 发业户(微信 / 邮件)。
|
||||
|
||||
## 系统流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 业户
|
||||
participant 财务
|
||||
participant Filament
|
||||
participant ConsumeAction
|
||||
participant PrepaidAccount
|
||||
participant Bill
|
||||
participant 数据库
|
||||
participant 监听器
|
||||
|
||||
Note over 业户,财务: 5 月物业费账单已出,张阿姨 balance=4200
|
||||
|
||||
财务->>Filament: ViewPrepaidAccount → ConsumeAction(选 Bill, 800)
|
||||
Filament->>ConsumeAction: handle(account, bill, 800)
|
||||
ConsumeAction->>PrepaidAccount: canOperate() ? Active=true
|
||||
ConsumeAction->>PrepaidAccount: community_id match Bill? yes
|
||||
ConsumeAction->>PrepaidAccount: balance >= 800? 4200≥800 yes
|
||||
ConsumeAction->>数据库: 开启事务
|
||||
ConsumeAction->>数据库: 1. 建 CO(type=Bill, +800, meta.fund_source=prepaid)
|
||||
ConsumeAction->>数据库: 2. 建 CollectionOrderBill 关联
|
||||
ConsumeAction->>PrepaidAccount: 3. consume(bill, 800)
|
||||
PrepaidAccount->>数据库: 建 PrepaidTransaction(consume, 4200→3400, related_bill_id)
|
||||
PrepaidAccount->>数据库: 更新 balance=3400
|
||||
ConsumeAction->>Bill: 4. recordPayment(800)
|
||||
Bill->>数据库: status=Paid
|
||||
ConsumeAction->>监听器: 5. 触发 CollectionOrderCompleted
|
||||
监听器->>数据库: 建 Receipt("物业费 ¥800")
|
||||
ConsumeAction->>数据库: 提交事务
|
||||
Filament-->>财务: 成功
|
||||
财务-->>业户: 推送 + 收据
|
||||
```
|
||||
|
||||
## 流水台账(本场景在累计流水中)
|
||||
|
||||
| 流水 | type | amount | balance_before | balance_after | related_bill_id | 备注 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | deposit | 5000 | 0 | 5000 | — | 首次充值 |
|
||||
| **2** | **consume** | **800** | **5000** | **4200** | **Bill #5月物业费** | **本场景** |
|
||||
| (后续 4 月 5 月各 800 ...) |
|
||||
|
||||
5 月账单进入 Paid 状态,张阿姨账户余额变 ¥3,400。
|
||||
|
||||
## 部分抵扣的特殊情况
|
||||
|
||||
若业户余额**不够全付**(例如余额 ¥500,账单 ¥800):
|
||||
|
||||
| 选项 | 当前实现 |
|
||||
|---|---|
|
||||
| 抵扣 ¥500,账单剩 ¥300 待付 | 看 `Bill::recordPayment()` 是否支持部分支付 |
|
||||
| 全部跳过(不抵)| 等业户充值或其他方式付 |
|
||||
|
||||
**当前推荐**:跳过,告知业户"余额不足,请充值或选其他方式付"。部分抵扣需 Bill 模块配合。
|
||||
|
||||
## 常见问题
|
||||
|
||||
> [!question] Modal 表单里"关联账单"下拉如何过滤?
|
||||
> 系统只显示:
|
||||
> - 与本账户同社区(community_id 一致)
|
||||
> - 业户本人(resident_id 一致)
|
||||
> - 状态 Unpaid
|
||||
> - 按 due_at 升序(最早到期的先,引导业务人员优先抵)
|
||||
>
|
||||
> 多个账单 → [[consume-multiple-bills-priority|按优先级抵扣]]
|
||||
|
||||
> [!question] 抵扣后业户问"我用预存款付的为啥收据写'物业费'?"
|
||||
> 这是**有意设计**(详见 [[consume-via-bill-collection-type]]):业户感知一致,不管怎么付,收据都长一样。如果业户想知道"是用预存款付的",可在小程序"我的账单"看到付款方式 = "预存款抵扣"。
|
||||
|
||||
> [!question] 抵扣失败如何排查?
|
||||
> 看后台 / 日志的错误信息:
|
||||
> - "账户冻结" → 解冻
|
||||
> - "跨社区不允许" → 业务人员选错账单 / 账户
|
||||
> - "余额不足" → 业户先充值
|
||||
> - "账单已 Paid" → 不要重复抵扣
|
||||
|
||||
> [!question] 月底 100+ 户挨个 Modal 抵扣太慢了吧?
|
||||
> 是的,这就是**月初批量自动抵扣 job** 的存在意义(详见 [[auto-deduction-design]])。**job 实现前**业务人员必须挨个手动。
|
||||
|
||||
> [!question] 已抵扣的账单想撤回怎么办?
|
||||
> 不可变流水设计。如果抵错(例如抵了别人的账单):
|
||||
> - 走退款 [[refund-partial-after-consume]] —— 但这退的是预存款余额,不是"撤销抵扣"
|
||||
> - 撤销账单需 Bill 模块支持 reverse,不在本场景
|
||||
> - 实际:**预防胜于补救**,Modal 表单提交前再三确认 Bill ID
|
||||
|
||||
## 异常分支
|
||||
|
||||
- 余额不够 → 业户先充 [[deposit-additional-topup]] 再来抵
|
||||
- 账户 Frozen → 先 [[unfreeze-after-verification]]
|
||||
- 多张账单一起抵 → [[consume-multiple-bills-priority]]
|
||||
- 计量类账单 → [[consume-meter-bill]]
|
||||
- 月初批量(未来)→ [[consume-batch-auto-monthly]]
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [[transaction-types]]
|
||||
- [[consume-via-bill-collection-type]]
|
||||
- [[account-state-machine]]
|
||||
- [[consume-multiple-bills-priority]]
|
||||
- [[consume-batch-auto-monthly]]
|
||||
- [[auto-deduction-design]]
|
||||
163
prop-acc/scenarios/prepaid/deposit-additional-topup.md
Normal file
163
prop-acc/scenarios/prepaid/deposit-additional-topup.md
Normal file
@@ -0,0 +1,163 @@
|
||||
---
|
||||
title: prop-acc · prepaid · 场景 - 已有账户追加充值
|
||||
aliases:
|
||||
- 追加充值预存款
|
||||
- 预存款续充
|
||||
- deposit-additional-topup
|
||||
- 场景-预存款追加充值
|
||||
tags:
|
||||
- 场景
|
||||
- prop-acc
|
||||
- 预存款
|
||||
- 充值
|
||||
audience:
|
||||
- 业户
|
||||
- 业务人员
|
||||
status: 已发布
|
||||
sub_feature: prepaid
|
||||
last_review: 2026-05-25
|
||||
code_version: 2026-05-22
|
||||
---
|
||||
|
||||
# 场景:已有账户追加充值
|
||||
|
||||
业户**已有 Active 预存款账户**,余额不够 / 想多存,继续充值。比首次开户简单 —— 不建账户,只加流水。
|
||||
|
||||
## 典型情境
|
||||
|
||||
> [!example] 真实情境
|
||||
> 张阿姨 3 个月前充了 ¥5,000 预存款,期间扣了 ¥2,400(物业费 800 × 3),余额 ¥2,600。下个月还要扣 ¥800 + ¥600 水电费,觉得余额勉强够,**再充 ¥3,000** 凑个整。
|
||||
|
||||
## 业户视角
|
||||
|
||||
### 第 1 步:到前台 / 小程序
|
||||
|
||||
跟物业管家说"我预存账户加 ¥3,000"。
|
||||
|
||||
### 第 2 步:付款
|
||||
|
||||
支付方式同首次充值。
|
||||
|
||||
### 第 3 步:拿收据
|
||||
|
||||
"预付款充值 ¥3,000"。
|
||||
|
||||
### 第 4 步:余额查看
|
||||
|
||||
后台 / 小程序看到:
|
||||
|
||||
- 上次余额 ¥2,600 + 本次 ¥3,000 = **当前余额 ¥5,600**
|
||||
- 后续账单自动从这扣
|
||||
|
||||
## 业务人员视角
|
||||
|
||||
> [!info] 与首次充值的差异
|
||||
> **不开新账户**,在既有账户上 `DepositAction` 加流水。
|
||||
|
||||
### 第 1 步:找到既有账户
|
||||
|
||||
后台 → 预存款 → 账户列表 → 按业户姓名 / 房号搜索 → 找到 Active 账户。
|
||||
|
||||
### 第 2 步:进 `ViewPrepaidAccount`
|
||||
|
||||
详情页右上角点 **`DepositAction`**(标签"充值")。
|
||||
|
||||
> [!warning] 按钮可见性
|
||||
> `DepositAction` 守护:`canOperate()`(Active only)+ Policy `->authorize('deposit')`。Frozen / Closed 灰化。
|
||||
|
||||
### 第 3 步:Modal 表单
|
||||
|
||||
| 字段 | 填什么 |
|
||||
|---|---|
|
||||
| **充值金额** | ¥3,000 |
|
||||
| **支付方式** | 现金 / 微信 / POS / 银行转账 |
|
||||
| **收款银行账户** | 微信/POS/转账选对应银行 |
|
||||
| **备注** | 选填 |
|
||||
|
||||
### 第 4 步:提交
|
||||
|
||||
系统调 `PrepaidAccount::deposit($amount, ...)`,事务内:
|
||||
|
||||
1. 模型层校验 `canOperate()`(Active only)
|
||||
2. 建 `CollectionOrder`(`type=Prepaid`,`actual=+3000`,`Completed`)
|
||||
3. 建 `PrepaidTransaction`(`type=deposit`,`amount=3000`,`balance_before=2600`,`balance_after=5600`,关联 CO)
|
||||
4. 更新 `PrepaidAccount.balance=5600`
|
||||
5. 触发 `CollectionOrderCompleted` → Listener 建 Receipt"预付款充值 ¥3,000"
|
||||
|
||||
### 第 5 步:给收据
|
||||
|
||||
打印 / 发微信。
|
||||
|
||||
## 系统流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 业户
|
||||
participant 前台
|
||||
participant Filament
|
||||
participant PrepaidAccount
|
||||
participant 数据库
|
||||
|
||||
业户->>前台: 给预存账户加 3000
|
||||
前台->>Filament: ViewPrepaidAccount → DepositAction(modal)
|
||||
Filament->>PrepaidAccount: deposit(3000, ...)
|
||||
PrepaidAccount->>PrepaidAccount: canOperate()? Active=true
|
||||
PrepaidAccount->>数据库: 开启事务
|
||||
PrepaidAccount->>数据库: 1. 建 CO (Prepaid, +3000, Completed)
|
||||
PrepaidAccount->>数据库: 2. 建 PrepaidTransaction (deposit, 2600→5600)
|
||||
PrepaidAccount->>数据库: 3. 更新 balance=5600
|
||||
PrepaidAccount->>监听器: 触发 CollectionOrderCompleted
|
||||
监听器->>数据库: 建 Receipt (预付款充值 ¥3,000)
|
||||
PrepaidAccount->>数据库: 提交
|
||||
Filament-->>前台: 成功
|
||||
前台->>业户: 收据
|
||||
```
|
||||
|
||||
## 流水台账(本场景在累计流水中的位置)
|
||||
|
||||
| 流水 | type | amount | balance_before | balance_after | 备注 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | deposit | 5000 | 0 | 5000 | 3 个月前首次充值 |
|
||||
| 2 | consume | 800 | 5000 | 4200 | 第 1 月物业费 |
|
||||
| 3 | consume | 800 | 4200 | 3400 | 第 2 月物业费 |
|
||||
| 4 | consume | 800 | 3400 | 2600 | 第 3 月物业费 |
|
||||
| **5** | **deposit** | **3000** | **2600** | **5600** | **本次追加** |
|
||||
|
||||
## 常见问题
|
||||
|
||||
> [!question] Frozen 账户能追加充值吗?
|
||||
> **不能**。`canOperate()` 只允许 Active。详见 [[exception-refund-on-frozen|三层守护]](deposit / consume / refund 都一样)。
|
||||
>
|
||||
> 如果业户硬要充:
|
||||
> - 系统层无法绕过(模型层兜底)
|
||||
> - **业务层** 需先 [[unfreeze-after-verification|解冻]] → 再充
|
||||
> - 不可"暂存钱等解冻后录入" —— 不合规
|
||||
|
||||
> [!question] Closed 账户能追加充值吗?
|
||||
> **不能**(同上)。需要开新账户,但**一户一账约束阻塞**(详见 [[one-account-per-resident]] "已知设计 gap")。
|
||||
|
||||
> [!question] 同时多笔追加(一天充两次)可以吗?
|
||||
> 可以。每次独立 Action,各自一笔 Transaction + CO + Receipt。账户 balance 累加。
|
||||
|
||||
> [!question] 充值过多担心退不出来?
|
||||
> 任何时候可走 [[refund-partial-after-consume]] 或 [[refund-full-resident-moveout]] 退余。预存款不像押金有"装修结束才能退"的业务节点,**随时可退**。
|
||||
|
||||
> [!question] 业户问"我能用别人的微信付吗?"
|
||||
> 系统不限制实际支付来源(微信扫码用谁付都行)。**业务上**:
|
||||
> - 账面缴款人是业户本人(`PrepaidAccount.community_user_profile_id` 不变)
|
||||
> - 实际付钱的是谁是业户自己的事
|
||||
> - 退款时**只退给账面缴款人**(业户本人),不是实际付钱的微信号
|
||||
|
||||
## 异常分支
|
||||
|
||||
- 业户从未充过 → 走 [[deposit-first-time]] 开户
|
||||
- 充错金额 → [[refund-partial-after-consume]]
|
||||
- 账户冻结 → 先 [[unfreeze-after-verification]] 解冻
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [[deposit-first-time]]
|
||||
- [[account-state-machine]]
|
||||
- [[consume-monthly-property-bill]]
|
||||
- [[refund-partial-after-consume]]
|
||||
- [[exception-refund-on-frozen]]
|
||||
187
prop-acc/scenarios/prepaid/deposit-first-time.md
Normal file
187
prop-acc/scenarios/prepaid/deposit-first-time.md
Normal file
@@ -0,0 +1,187 @@
|
||||
---
|
||||
title: prop-acc · prepaid · 场景 - 首次开户充值 5000
|
||||
aliases:
|
||||
- 首次充值预存款
|
||||
- 开预存款账户
|
||||
- deposit-first-time
|
||||
- 场景-首次充值预存款
|
||||
tags:
|
||||
- 场景
|
||||
- prop-acc
|
||||
- 预存款
|
||||
- 充值
|
||||
audience:
|
||||
- 业户
|
||||
- 业务人员
|
||||
status: 已发布
|
||||
sub_feature: prepaid
|
||||
last_review: 2026-05-25
|
||||
code_version: 2026-05-22
|
||||
---
|
||||
|
||||
# 场景:首次开户充值 5000
|
||||
|
||||
业户**第一次**开预存款账户并充值。一户一账约束:同业户在同社区只能开一个,系统在提交时校验。
|
||||
|
||||
## 典型情境
|
||||
|
||||
> [!example] 真实情境
|
||||
> 张阿姨(12-3-501)每月物业费 ¥800,觉得月月去前台缴麻烦,跟物业管家说:"我一次充半年,以后从这里自动扣行不行?"
|
||||
>
|
||||
> 物业管家:"行,我帮您开个预存款账户,您充 ¥5,000 进去,以后账单出来自动从这里扣。"
|
||||
|
||||
## 业户视角
|
||||
|
||||
### 第 1 步:跟物业说要充值
|
||||
|
||||
- 到前台 / 物业管家微信 / 小程序(若开通)
|
||||
- 表达"我想预存,以后自动扣账单"
|
||||
|
||||
### 第 2 步:确认充值金额
|
||||
|
||||
通常建议:**3-6 个月账单的金额**。少了频繁充值,多了占用资金。
|
||||
|
||||
- 月物业费 ¥800 → 充 ¥3,000-¥5,000(够 3-6 个月)
|
||||
- 加水电费一起 → 充 ¥5,000-¥10,000
|
||||
|
||||
### 第 3 步:付款
|
||||
|
||||
支付方式:
|
||||
|
||||
- **现金**
|
||||
- **微信扫码**
|
||||
- **POS 刷卡**
|
||||
- **银行转账**
|
||||
|
||||
### 第 4 步:拿收据
|
||||
|
||||
"预付款充值 ¥5,000"。
|
||||
|
||||
> [!info] 这张收据是普通正数收据
|
||||
> 跟付物业费的收据长一样,只是文案不同。详见 [[transaction-types]]。
|
||||
|
||||
### 第 5 步:后续
|
||||
|
||||
- 物业费账单出来 → 业务人员手动 / (未来)自动抵扣 → 您收到"物业费 ¥800" 收据
|
||||
- 余额 ¥4,200 留账户里,下月继续扣
|
||||
|
||||
## 业务人员视角
|
||||
|
||||
### 第 1 步:核实业户身份
|
||||
|
||||
- 业户档案存在(否则要先建)
|
||||
- 业户当前社区(决定 community_id)
|
||||
|
||||
### 第 2 步:打开后台
|
||||
|
||||
后台 → 预存款 → **新建账户**(`ListPrepaidAccounts` 的 Create 按钮)。
|
||||
|
||||
### 第 3 步:填表单
|
||||
|
||||
| 字段 | 填什么 |
|
||||
|---|---|
|
||||
| **业户档案(`community_user_profile_id`)** | 通过房号 / 手机号 / 姓名找到张阿姨 |
|
||||
| **社区(`community_id`)** | 自动带入业户所在社区(或手动选) |
|
||||
| **首次充值金额** | ¥5,000 |
|
||||
| **支付方式** | 现金 / 微信 / POS / 银行转账 |
|
||||
| **收款银行账户** | 微信/POS/转账选对应银行;现金可空 |
|
||||
| **备注** | 选填,如 "业户要求月度自动扣账" |
|
||||
|
||||
> [!warning] 一户一账校验
|
||||
> 系统提交时检查 `(community_id, community_user_profile_id)` 是否已存在:
|
||||
> - 已有 Active → 提示"该业户在本社区已有预存款账户,请直接充值" → 引导到 [[deposit-additional-topup]]
|
||||
> - 已有 Frozen → 提示"账户冻结中,请先解冻"
|
||||
> - 已有 Closed → 当前阻塞(见 [[one-account-per-resident]] "已知设计 gap" 段)
|
||||
> - 无 → 正常建账
|
||||
|
||||
### 第 4 步:提交
|
||||
|
||||
系统在事务内:
|
||||
|
||||
1. 建 `PrepaidAccount`(`status=Active`,`balance=5000`)
|
||||
2. 建 `CollectionOrder`(`collection_type=Prepaid`,`actual_amount=+5000`,`status=Completed`)
|
||||
3. 建 `PrepaidTransaction`(`type=deposit`,`amount=5000`,`balance_before=0`,`balance_after=5000`,关联 CO)
|
||||
4. 触发 `CollectionOrderCompleted` 事件
|
||||
5. Listener `generatePrepaidReceiptItems` 建 Receipt + ReceiptItem"预付款充值 ¥5,000"
|
||||
|
||||
### 第 5 步:打印 / 发收据
|
||||
|
||||
后台收据列表找到新生成 Receipt → 打印 / 微信发业户。
|
||||
|
||||
## 系统流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 业户
|
||||
participant 前台
|
||||
participant Filament
|
||||
participant 数据库
|
||||
participant 监听器
|
||||
|
||||
业户->>前台: 充 5000 预存款
|
||||
前台->>Filament: ListPrepaidAccounts → Create
|
||||
Filament->>数据库: 校验 unique(community_id, profile_id) → 通过
|
||||
Filament->>数据库: 开启事务
|
||||
Filament->>数据库: 1. 建 PrepaidAccount (Active, balance=5000)
|
||||
Filament->>数据库: 2. 建 CollectionOrder (type=Prepaid, +5000, Completed)
|
||||
Filament->>数据库: 3. 建 PrepaidTransaction (deposit, 0→5000, 关联 CO)
|
||||
Filament->>监听器: 4. 触发 CollectionOrderCompleted
|
||||
监听器->>数据库: 5. 建 Receipt ("预付款充值 ¥5,000")
|
||||
Filament->>数据库: 提交事务
|
||||
Filament-->>前台: 成功 + 显示新账户
|
||||
前台->>业户: 给收据
|
||||
```
|
||||
|
||||
## 与 deposit 首次缴款的对比
|
||||
|
||||
| 维度 | 押金首次缴款 | **预存款首次充值** |
|
||||
|---|---|---|
|
||||
| 表单字段 | payer_type / fee_type / asset 等多个 | **只需 community_user_profile** |
|
||||
| 业户/缴款人差异 | 缴款人可与业户不同(装修公司代缴)| **缴款人必须是业户本人** |
|
||||
| CollectionType | Deposit | **Prepaid** |
|
||||
| 同业户多账户 | ✅ 多种费类多账户 | ❌ **一户一账** |
|
||||
| 关账机制 | 退完自动 Closed | 退完仍 Active(可继续充) |
|
||||
|
||||
## 常见问题
|
||||
|
||||
> [!question] 业户已有 Closed 账户,如何开新?
|
||||
> 当前系统阻塞(unique 约束)。可选:
|
||||
> - 联系运维 tinker 改账户名(罕见)
|
||||
> - 业务上说服业户用现金 / 微信付,不开新预存账户
|
||||
> - 系统层加 `WHERE status != 'closed'` 软约束(待业务方拍板)
|
||||
>
|
||||
> 详见 [[one-account-per-resident]] "已知设计 gap" 段。
|
||||
|
||||
> [!question] 跨社区业户(同时住两个小区)怎么开?
|
||||
> 各社区独立账户(各自 unique)。在 A 社区开一个、B 社区开一个,各自独立余额。
|
||||
|
||||
> [!question] 充值金额有上限吗?
|
||||
> 系统层面无硬性上限。业务上建议:
|
||||
> - 不超过 12 个月账单合计(避免资金被冻在物业账上太久)
|
||||
> - 单笔大额(>10000)走银行转账,留银行流水
|
||||
> - 单笔超 50000 需财务上报(防风险)
|
||||
|
||||
> [!question] 充错金额(把 5000 录成 50000)怎么办?
|
||||
> 不要改流水。建一笔 `Refund` ¥45,000(走 [[refund-partial-after-consume]] 流程),业户拿到红字"预付款退款 ¥-45,000",事后审计完整可追。
|
||||
|
||||
> [!question] 业户不知道这账户怎么用,需要培训吗?
|
||||
> 关键点:
|
||||
> - 余额能抵物业费 / 水电费 / 其他账单
|
||||
> - 余额随时可查(小程序 / 微信对账单)
|
||||
> - 余额随时可退(业务人员后台操作)
|
||||
> - 余额不够时账单不会自动扣 → 业户仍需补缴
|
||||
|
||||
## 异常分支
|
||||
|
||||
- 业户已有账户 → [[deposit-additional-topup]]
|
||||
- 业户充错金额想撤 → [[refund-partial-after-consume]](走部分退款)
|
||||
- 业户后悔不想用预存了 → [[refund-full-resident-moveout]] + [[close-resident-moveout]]
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [[prepaid-account-vs-transaction]]
|
||||
- [[account-state-machine]]
|
||||
- [[one-account-per-resident]]
|
||||
- [[transaction-types]]
|
||||
- [[deposit-additional-topup]]
|
||||
- [[consume-monthly-property-bill]]
|
||||
180
prop-acc/scenarios/prepaid/deposit-via-miniapp-pending.md
Normal file
180
prop-acc/scenarios/prepaid/deposit-via-miniapp-pending.md
Normal file
@@ -0,0 +1,180 @@
|
||||
---
|
||||
title: prop-acc · prepaid · 场景 - 小程序在线充值(待补)
|
||||
aliases:
|
||||
- 小程序充值预存款
|
||||
- 线上充值预存款
|
||||
- deposit-via-miniapp-pending
|
||||
- 场景-小程序充值预存款
|
||||
tags:
|
||||
- 场景
|
||||
- prop-acc
|
||||
- 预存款
|
||||
- 充值
|
||||
- 待补
|
||||
audience:
|
||||
- 业户
|
||||
- 产品
|
||||
- 架构师
|
||||
status: 草稿
|
||||
sub_feature: prepaid
|
||||
last_review: 2026-05-25
|
||||
code_version: 2026-05-22
|
||||
---
|
||||
|
||||
# 场景:小程序在线充值(待补)
|
||||
|
||||
> [!warning] 本场景**代码未实现**
|
||||
> 当前所有充值都是**业务人员后台手动触发**。业户**没有自助充值入口**(微信小程序 / 公众号 / H5 都没接入)。本文档描述设计意图,等支付网关对接时一起落地。
|
||||
>
|
||||
> issue.md Q4 "待补" 段记录:
|
||||
> > 小程序在线充值 + 退款 webhook:同保证金模块,等支付网关对接时一起做
|
||||
|
||||
## 为什么这个场景重要
|
||||
|
||||
预存款的**真正价值**是业户**自助**预存 + 系统自动抵账单。如果业户每次充值都要"跑前台 / 找物业管家",体验跟去前台月月缴费没区别,预存款产品价值大打折扣。
|
||||
|
||||
**自助充值是产品落地的必备入口**。
|
||||
|
||||
## 业务场景(目标态)
|
||||
|
||||
### 业户视角
|
||||
|
||||
> [!example] 真实情境(目标态)
|
||||
> 陈先生(年轻业主)某晚 11 点查看本月物业费账单,看到余额不够,马上在小程序"我的预存款"页面充值:
|
||||
>
|
||||
> 1. 点"立即充值"
|
||||
> 2. 选金额(500 / 1000 / 3000 / 5000 / 自定义)
|
||||
> 3. 弹出微信支付确认
|
||||
> 4. 输入密码 / 指纹 → 付款成功
|
||||
> 5. 小程序 3 秒后提示"充值成功,余额已到账"
|
||||
>
|
||||
> 第二天物业费账单自动从余额扣,陈先生收到推送"已抵扣物业费 ¥800"。
|
||||
|
||||
### 业务人员视角
|
||||
|
||||
业务人员**几乎不感知**:
|
||||
|
||||
- 不需要在后台手动建账户 / 录充值
|
||||
- 月底对账时,看 CollectionOrder 列表多了一批 `payment_channel=微信`、`fund_source=external` 的预存款充值单
|
||||
- 异常(支付掉单 / 超时未付)由系统自动处理
|
||||
|
||||
## 关键技术挑战
|
||||
|
||||
### 1. 支付网关对接
|
||||
|
||||
| 选项 | 优 | 缺 |
|
||||
|---|---|---|
|
||||
| 微信支付商户号 | 业户熟悉,转化高 | 资质要求高,手续费 0.6% |
|
||||
| 支付宝 | 大额支付习惯 | 同上 |
|
||||
| 银联 / 网银 | 大额转账 | 体验差 |
|
||||
|
||||
**推荐**:微信支付 + 支付宝双通道,与一次性收费 B 流复用([[../adhoc/flow-b-miniapp-wechat-pay|adhoc B 流]])。
|
||||
|
||||
### 2. CollectionOrder 状态机
|
||||
|
||||
复用与 adhoc B 流相同的 Pending → Completed 流程([[../adhoc/flow-a-vs-flow-b|A 流与 B 流]]):
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant 业户
|
||||
participant 小程序
|
||||
participant 系统
|
||||
participant 支付网关
|
||||
|
||||
业户->>小程序: 选 5000 充值
|
||||
小程序->>系统: 建 CollectionOrder(type=Prepaid, +5000, **status=Pending**)
|
||||
系统-->>小程序: 返回订单号 + 锁定金额
|
||||
小程序->>支付网关: 调起微信支付
|
||||
业户->>支付网关: 输入密码 / 指纹付款
|
||||
支付网关->>系统: 支付回调 webhook
|
||||
系统->>系统: 校验签名 + 金额
|
||||
系统->>系统: CO.status = Completed
|
||||
系统->>系统: 调 PrepaidAccount::deposit(5000)
|
||||
系统->>系统: 触发 CollectionOrderCompleted → Receipt
|
||||
系统-->>业户: 推送"充值成功"
|
||||
```
|
||||
|
||||
### 3. 自动开户
|
||||
|
||||
如果业户在小程序充值时**还没有预存款账户**:
|
||||
|
||||
| 方案 A:必须先开户 | 方案 B:充值时自动开户 |
|
||||
|---|---|
|
||||
| 业户去前台开户 → 小程序充值 | 小程序充值流程内自动建账户 |
|
||||
| 体验割裂(为啥要去前台?) | 体验顺畅 |
|
||||
| 业务人员必须介入 | 全程自动 |
|
||||
|
||||
**推荐方案 B**:充值时若 `PrepaidAccount` 不存在,自动建 Active 账户(`opened_at` = 充值时间)。
|
||||
|
||||
### 4. 失败处理
|
||||
|
||||
| 失败场景 | 处理 |
|
||||
|---|---|
|
||||
| 业户付了款,回调延迟 | CO 仍 Pending → 业户重复点充值 → 防重(检查 24h 内同业户同金额 Pending CO)|
|
||||
| 业户付了款,回调丢失 | 定时任务扫描 Pending > 30 min 的 CO,主动查询支付网关 |
|
||||
| 业户取消支付 | CO 翻 Failed,余额不变 |
|
||||
| 业户付款金额与订单不符(异常)| 拒绝,告警,人工介入 |
|
||||
|
||||
### 5. 退款 webhook
|
||||
|
||||
业户在小程序自助申请退款:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
业户->>小程序: 申请退余 3000
|
||||
小程序->>系统: 建退款申请单(待业务审批)
|
||||
Note over 系统: 业务审批通过后:
|
||||
系统->>支付网关: 调退款 API
|
||||
支付网关->>系统: 退款回调 webhook
|
||||
系统->>系统: 建红字 CO + PrepaidTransaction(refund)
|
||||
系统-->>业户: 推送"退款成功"
|
||||
```
|
||||
|
||||
**关键**:不像后台手动退款是"业务人员决定退多少",小程序自助退款必须**先建审批工单**,业务方审核(防止业户恶意大额退款),通过后才走支付网关退款。
|
||||
|
||||
## 待讨论 / 决策
|
||||
|
||||
| 问题 | 选项 |
|
||||
|---|---|
|
||||
| **支付通道** | 微信支付 / 支付宝 / 银联 / 全部都开 |
|
||||
| **充值起步** | 最低 100 / 500 / 1000 |
|
||||
| **充值上限** | 单笔 5000 / 10000 / 不限 |
|
||||
| **自动开户** | 充值时自动建 Active 账户 vs 业户必须先去前台 |
|
||||
| **退款审批** | 业户提交即退 vs 业务审批后退 / 大额(>5000)需审批 |
|
||||
| **超时未付** | 30 分钟自动取消 / 24 小时 / 不取消(避免业户晚付被取消)|
|
||||
|
||||
业务方拍板前,以上问题需明确。
|
||||
|
||||
## 当前替代方案(等代码就位前)
|
||||
|
||||
业户想自助充值的,目前只能:
|
||||
|
||||
| 方法 | 体验 |
|
||||
|---|---|
|
||||
| 联系物业管家微信 → 转账给物业财务 → 财务后台录入 | 还行,但有时延 |
|
||||
| 到前台缴 → 现金 / POS | 慢、要跑 |
|
||||
| 银行直接对公转账 → 备注业户姓名房号 → 财务认领 | 慢 + 复杂 |
|
||||
|
||||
**所有路径都需要业务人员介入** —— 体验远不如小程序自助。这就是为什么这个场景"产品价值高、紧迫性强"。
|
||||
|
||||
## 关联场景
|
||||
|
||||
实现后,以下场景的设计会发生关联变化:
|
||||
|
||||
- [[deposit-first-time]] / [[deposit-additional-topup]]:多一条"业户自助充值"路径,业务人员手动充值场景变少(但仍需保留,给老业主用)
|
||||
- [[consume-batch-auto-monthly]]:小程序充值后自动到账,月初批量自动抵扣 job 可立即用上新余额
|
||||
- [[refund-full-resident-moveout]] / [[refund-partial-after-consume]]:多一条"业户小程序自助申请"路径,需要审批流
|
||||
|
||||
## 异常分支(未来落地后)
|
||||
|
||||
- 支付网关掉单 / 超时 → 系统重试 / 业务介入
|
||||
- 业户充错金额 → 走退款流程
|
||||
- 业户重复提交 → 防重检测
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [[auto-deduction-design]]
|
||||
- [[deposit-first-time]]
|
||||
- [[deposit-additional-topup]]
|
||||
- [[../adhoc/flow-a-vs-flow-b|A 流与 B 流]](adhoc 的小程序在线模式,参考实现)
|
||||
- [[../adhoc/flow-b-miniapp-wechat-pay|adhoc 小程序微信付]]
|
||||
Reference in New Issue
Block a user