5.8 KiB
title, aliases, tags, audience, status, sub_feature, last_review, code_version
| title | aliases | tags | audience | status | sub_feature | last_review | code_version | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| prop-acc · prepaid · 场景 - 部分消费后退余(不自动关账) |
|
|
|
已发布 | prepaid | 2026-05-25 | 2026-05-22 |
场景:部分消费后退余(不自动关账)
业户部分使用预存款后,想退余下一部分(不全退,继续保留账户)。退完仍 Active,业户可后续继续充值复用。本场景突出 prepaid 与 deposit 的关键差异:零余额不自动关账,部分余额更不会。
典型情境
[!example] 真实情境 陈先生 3 个月前充了 ¥5,000 预存款,期间扣了 ¥2,400(3 个月物业费),余额 ¥2,600。他最近现金流紧张,想先退 ¥1,500 应急,留 ¥1,100 在账户继续扣物业费。
业户视角
第 1 步:跟物业说要退一部分
- "我想从预存款退 ¥1,500,留点继续用"
- 提供退款渠道
第 2 步:等退款
- 业务人员核实余额、操作
第 3 步:收到红字收据 + 退款
- 红字收据"预付款退款 ¥-1,500"
- 银行 / 微信收到 ¥1,500
第 4 步:账户保持 Active
- 小程序"我的预存款"显示余额 ¥1,100
- 仍可继续抵账单
- 后续可继续充值
[!info] 与 deposit 的核心差异 deposit 退完余额到 0 会自动 Closed。prepaid 退完无论余额多少都不自动关,业户随时可继续用。
业务人员视角
第 1 步:打开账户
后台 → 预存款 → 陈先生账户(Active,balance=2600)→ 进 ViewPrepaidAccount。
第 2 步:RefundAction Modal
| 字段 | 填什么 |
|---|---|
| 退款金额 | ¥1,500(不是全额,手动改) |
| 退款渠道 | 微信 / 银行 |
| 备注 | 选填,如 "业户申请部分退款" |
[!warning] 易错点 Modal 默认带入当前余额全额(¥2,600)。必须手动改为 ¥1,500,否则就成了全退。
第 3 步:提交
系统调 RefundFromPrepaidAccountAction,事务内:
- 校验
canOperate() - 校验金额 ≤ 余额(1500 ≤ 2600 ✓)
- 建
CollectionOrder(type=Prepaid,actual=-1500红字,Completed) - 调
account.refund(1500):- 加
PrepaidTransaction(type=refund, 2600→1100,关联 CO) - 更新 balance=1100
- 加
- 不关账(余额非 0)
- 触发监听器 → Receipt"预付款退款 ¥-1,500"
第 4 步:走线下退款 + 给收据
银行 / 微信退 ¥1,500;红字收据交业户。账户保持 Active,余额 ¥1,100。
第 5 步:告知业户
"已退 ¥1,500,账户还有 ¥1,100 可继续抵账单"。
系统流程
sequenceDiagram
participant 业户
participant 财务
participant Filament
participant 数据库
Note over 业户: 余额 2600,要退 1500
业户->>财务: 退 1500
财务->>Filament: ViewPrepaidAccount → RefundAction(modal, **改成 1500**)
Filament->>数据库: RefundFromPrepaidAccountAction
数据库->>数据库: 建 CO(-1500 红字) + PrepaidTransaction(refund, 2600→1100)
数据库->>数据库: balance=1100(**不关账**)
数据库->>监听器: 触发监听器 → Receipt("预付款退款 ¥-1,500")
财务-->>业户: 微信退 1500 + 红字收据 + 告知余额 1100
流水台账(累计)
| 流水 | 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 | refund | 1500 | 2600 | 1100 | 本场景 |
账户余额 ¥1,100,仍 Active,后续可继续抵账单或充值。
与 deposit 退款的差异
| 维度 | deposit 部分退款(refund-partial-after-forfeit) | prepaid 部分退款(本场景) |
|---|---|---|
| 退款产生的 CO 类型 | type=Deposit, -N 红字 | type=Prepaid, -N 红字 |
| 退完余额 0 | 自动 Closed | 仍 Active |
| 退完余额非 0 | 仍 Active(deposit 也允许部分退后继续动) | 仍 Active |
| 业务背景 | 押金扣罚 + 退余 | 业户应急需现金,部分提取 |
常见问题
[!question] 退完余额变 0,会自动关账吗? 不会。即使全退到 0,prepaid 仍保持 Active。详见 account-state-machine"零余额不自动关账"段 + close-with-zero-balance-decision。
[!question] 业务人员退多了(改余额时手抖)? 系统会校验
amount ≤ balance守护拦截。例如余额 2600,改成 3000 提交 → 抛错 "amount exceeds balance"。预防:Modal 提交前再三确认数字。
[!question] 业户想退完了又改主意,要充回去? 当然可以。直接走 deposit-additional-topup 把钱充回账户即可。账户一直 Active 没动过。
[!question] 业户拿到红字收据后困惑"我没买东西啊为什么收据是负数"? 解释:
- 红字 = 钱从物业流出 / 回到您手里
- 这不是消费收据,是退款收据
- 详见 ../deposit/red-receipt-design(deposit 模块的概念,prepaid 复用相同设计)
[!question] 业户问"我现在余额 1100,还能扣账单吗?" 当然能。账户 Active,余额 > 0,正常用。物业费下月扣完后余额会变 ¥300(假设 ¥800 月费)。
异常分支
- 全额退 → refund-full-resident-moveout
- Frozen 状态退 → 先 unfreeze-after-verification 再退
- 退完想关账 → 走 close-with-zero-balance-decision
- 业户搬走全退 + 关账 → refund-full-resident-moveout + close-resident-moveout