7.5 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 · billing · 场景 - 单张账单收款 |
|
|
|
已发布 | billing | 2026-05-26 | 2026-05-22 |
场景:单张账单收款
业户单张账单付款(物业费 / 水费 / 电费的某一张),业务人员后台触发 CollectPaymentAction。最基础高频的收款场景。
典型情境
[!example] 真实情境 张阿姨 5 月物业费 ¥800 账单已生成,她下午到物业前台:
- "我交 5 月物业费"
- 业务人员小李打开张阿姨账户 → 找到 5 月物业费账单 → 收款
业户视角
第 1 步:到前台 / 小程序
带:
- 钱(现金 / 微信 / POS 卡)
- 房号 / 姓名(身份证)
第 2 步:告诉业务人员要付哪张账单
"我交 5 月物业费"
业务人员从系统找到对应账单。
第 3 步:确认金额 + 付款方式
业务人员告诉张阿姨:
"您 5 月物业费 ¥800,请选付款方式"
| 付款方式 | 操作 |
|---|---|
| 现金 | 给钱 → 找零 |
| 微信扫码 | 业务人员出示物业收款码 → 业户扫 |
| POS 刷卡 | 业户给银行卡 → POS 机刷 |
| 银行转账 | 业户给凭证(线下转账已到账) |
第 4 步:拿收据
- 纸质:当场打印
- 电子:发到业户微信 / 邮箱
[!success] 完成 账单状态从 Unpaid → Paid。业户带收据离开,5 分钟内搞定。
业务人员视角
第 1 步:找账单
后台 → 账单 → 列表 → 按业户姓名 / 房号 / 期次过滤 → 找到张阿姨的 5 月物业费(Unpaid,¥800)→ 进 ViewBill。
或者:
- 后台 → 业户 → 找到张阿姨 → "她的账单"标签 → 看 Unpaid 列表 → 选
第 2 步:点击 CollectPaymentAction(标签"收款")
右上角状态管理组。
[!warning] 按钮可见性
CollectPaymentAction守护:canBePaid()(Unpaid / Partial)+->authorize('collect')。Paid / Void / Suspended / Processing 灰化。
Modal 表单:
| 字段 | 填什么 |
|---|---|
| 收款金额 | ¥800(默认全额,可改为部分) |
支付方式(payment_channel_id) |
现金 / 微信 / POS / 银行转账 |
收款银行账户(bank_account_id) |
微信/POS/转账选对应银行账户;现金可空 |
| 收款备注 | 选填,如"业户现场付款" |
第 3 步:提交
系统在一个事务内:
- 校验 Bill 可付(
canBePaid= Unpaid / Partial) - 校验金额 ≤ Bill 剩余应付(
amount - paid_amount) - 建
CollectionOrder(type=Bill,actual_amount=+800,status=Completed,payment_channel,meta.fund_source=external) - 建
CollectionOrderBill(bill_id,collection_order_id,allocated_amount=800) - 更新
Bill.paid_amount += 800 - 更新
Bill.status:若 paid_amount = amount →Paid;若 < amount →Partial - 触发
CollectionOrderCompleted事件 - Listener 自动建
Receipt+ReceiptItem(文案"物业费 ¥800") - 写 activitylog(可选,具体看实现)
第 4 步:给业户收据
后台找到新生成 Receipt → 打印 / 微信发。
系统流程
sequenceDiagram
participant 业户
participant 业务[业务人员]
participant Filament
participant Action[CollectPaymentAction]
participant DB
participant Listener
业户->>业务: 付物业费 800
业务->>Filament: ViewBill → CollectPaymentAction(modal)
Filament->>Action: handle(bill, 800, channel, bank)
Action->>Action: canBePaid()? Unpaid=true
Action->>Action: 800 ≤ remaining(800)? yes
Action->>DB: 开启事务
Action->>DB: 1. 建 CollectionOrder(type=Bill, +800, Completed)
Action->>DB: 2. 建 CollectionOrderBill(allocated=800)
Action->>DB: 3. Bill.paid_amount=800
Action->>DB: 4. Bill.status=Paid(800=800)
Action->>Listener: 5. 触发 CollectionOrderCompleted
Listener->>DB: 6. 建 Receipt("物业费 ¥800")
Action->>DB: 提交事务
Filament-->>业务: 成功通知
业务-->>业户: 收据
部分付场景(business 上常见)
业户只想付 ¥300(全额 ¥800):
Modal 表单:
- 收款金额:300(手动改)
- 支付方式:现金
- 备注:"暂时只能付一部分"
提交后:
- Bill.paid_amount = 300
- Bill.status: Unpaid → Partial
- 建 CollectionOrder(+300)+ CollectionOrderBill(allocated=300)
业户后续补付 ¥500 → 同样走 CollectPaymentAction → 第 2 笔 CollectionOrderBill → Bill 收齐 → Paid。
数据示例(完整流水)
业户付 ¥800 后:
Bill 表
| 字段 | 值 |
|---|---|
id |
12345 |
amount |
800 |
paid_amount |
800 |
status |
Paid |
CollectionOrderBill 表
| 字段 | 值 |
|---|---|
bill_id |
12345 |
collection_order_id |
67890 |
allocated_amount |
800 |
CollectionOrder 表
| 字段 | 值 |
|---|---|
id |
67890 |
collection_type |
Bill |
actual_amount |
+800 |
payment_channel_id |
微信 |
status |
Completed |
meta.fund_source |
external |
Receipt 表
| 字段 | 值 |
|---|---|
collection_order_id |
67890 |
amount |
+800 |
| line_items | [{ 物业费(5月), 800 }] |
常见问题
[!question] 业户付的钱与账单金额不一致(多付 / 少付)?
情况 处置 少付 走部分付 Partial 状态;后续补付 多付 不应该(Modal 守护 amount ≤ remaining)。如果业务上业户给的钱多,找零给业户(系统层面只收账单的金额)
[!question] 业户付错账单(本想付物业费,付到电费)? 业务人员可:
- 立即作废这笔 CollectionOrder(走 void-paid-bill 类似流程)+ 重新对正确账单收款
- 或者留这笔不动(资金确实到账)+ 业务人员手工调整 CollectionOrderBill 的 allocated_amount(危险,会破坏审计)
推荐第一种(走作废 + 重收)。
[!question] Frozen Bill 能收款吗? 不能。
canBePaid()只允许 Unpaid / Partial。Suspended 状态需先 resume-bill。
[!question] 已付的 Bill 能再收款吗? 不能。
canBePaid()Paid 时返 false。理论上 Bill 已经付清。
[!question] 业户预存款够付,业务人员怎么操作? 看自动 / 手动:
- 自动(待补的 ../prepaid/auto-deduction-design):业务人员不操作,系统自动
- 手动:业务人员在
ViewBill→ 走CollectPaymentAction选"预存款抵扣"(或专用 Action)→ 详见 collect-via-prepaid-auto
[!question] 收款时 PaymentChannel 写错(选了微信实际是现金)? CollectionOrder 一经创建通常不可改字段。错了:
- 走作废(详见 void-paid-bill)+ 重新建
- 或 tinker 改字段(运维 + 留审计)
预防:Modal 提交前再三确认。
[!question] activitylog 记什么? 详见 smart-bulk-delete-design activitylog 设计。CollectPayment 通常也记一条 activitylog:event=collected,properties 含 amount / payment_channel / receipt_id。
异常分支
- 部分付场景 → exception-partial-payment
- 批量付(多张账单一起付)→ collect-payment-batch
- 预存款抵 → collect-via-prepaid-auto
- 收款错了想撤 → void-paid-bill
- Bill 挂起中无法收 → resume-bill
- 逾期账单催收 → exception-overdue-bills