Files
uniprop-manual/prop-acc/scenarios/billing/collect-payment-single.md
2026-05-26 01:03:15 +08:00

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 · 场景 - 单张账单收款
单张收款
收款
CollectPaymentAction
collect-payment-single
场景-单张账单收款
场景
prop-acc
账单
收款
业户
业务人员
已发布 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 步:提交

系统在一个事务内:

  1. 校验 Bill 可付(canBePaid = Unpaid / Partial)
  2. 校验金额 ≤ Bill 剩余应付(amount - paid_amount)
  3. CollectionOrder(type=Bill,actual_amount=+800,status=Completed,payment_channel,meta.fund_source=external)
  4. CollectionOrderBill(bill_id,collection_order_id,allocated_amount=800)
  5. 更新 Bill.paid_amount += 800
  6. 更新 Bill.status:若 paid_amount = amount → Paid;若 < amount → Partial
  7. 触发 CollectionOrderCompleted 事件
  8. Listener 自动建 Receipt + ReceiptItem(文案"物业费 ¥800")
  9. 写 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。

详见 exception-partial-payment

数据示例(完整流水)

业户付 ¥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] 业户预存款够付,业务人员怎么操作? 看自动 / 手动:

[!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。

异常分支

相关文档