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

7.8 KiB
Raw Blame History

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 · 场景 - 同业户多账单批量收款
批量收款
BatchCollectPaymentAction
一次付多张
collect-payment-batch
场景-同业户批量收款
场景
prop-acc
账单
收款
业户
业务人员
已发布 billing 2026-05-26 2026-05-22

场景:同业户多账单批量收款

业户本月有多张账单(物业费 + 水电气费 + 其他),想一次性付清。业务人员走 BatchCollectPaymentAction,一笔 CollectionOrder 关联多张 Bill(走 CollectionOrderBill 多对多)。

典型情境

[!example] 真实情境 张阿姨本月有 4 张账单:

账单 金额
5 月物业费 ¥800
5 月水费 ¥54
5 月电费 ¥168
5 月燃气 ¥30
合计 ¥1,052

张阿姨到前台:"4 张账单我一次性付清,微信扫码"。业务人员1 笔操作完成 4 张账单收款。

业户视角

第 1 步:告诉业务人员要付哪些

"我把本月 4 张账单都付了,微信扫码"

第 2 步:确认金额

业务人员说:"4 张账单合计 ¥1,052,微信扫这个码"。

第 3 步:微信付

业户扫码 → 输密码 / 指纹 → 付 ¥1,052。

第 4 步:拿收据

可能是:

  • 一张 Receipt 含 4 行明细(物业费 ¥800 / 水费 ¥54 / ...)
  • 或 4 张独立 Receipt(每张账单一张)

具体看实现。业户体验上前者更好(一张收据看全部)。

业务人员视角

第 1 步:找业户

后台 → 业户 → 找到张阿姨 → "她的账单"标签 → 看到 4 张 Unpaid。

或:后台 → 账单 → 列表 → 过滤业户=张阿姨 + 状态=Unpaid。

第 2 步:选中多张账单

Table 上勾选 4 张账单 → 顶部 "批量收款" 按钮(BatchCollectPaymentAction)。

或:后台 → 业户视图 → "批量收款"(若 UI 支持单业户聚合)。

第 3 步:Modal 表单

字段 填什么
选中账单数 4 张(显示)
合计金额 ¥1,052(自动算)
支付方式 微信
收款银行账户 物业微信账户
备注 选填,如 "业户本月全套缴"

第 4 步:提交

系统在一个事务内:

  1. 校验每张 Bill 可付(canBePaid())
  2. 1 个 CollectionOrder(type=Bill,actual_amount=+1052,status=Completed)
  3. 4 个 CollectionOrderBill(每张账单一个,各自 allocated_amount = 该账单金额)
  4. 4 张 Bill 各自 paid_amount = amount,status = Paid
  5. 触发 CollectionOrderCompleted 事件
  6. Listener 建 Receipt(可能含 4 个 line_items)

第 5 步:给收据

后台找到 Receipt → 打印 / 微信发。

系统流程

sequenceDiagram
    participant 业户
    participant 业务
    participant Filament
    participant Action[BatchCollectPaymentAction]
    participant DB

    业务->>Filament: BillsList → 选 4 张 → 批量收款
    Filament->>Action: handle(bills, channel, bank)
    Action->>Action: 每张 Bill 校验 canBePaid

    Action->>DB: 开启事务
    Action->>DB: 1. 建 CollectionOrder(+1052, Completed)

    loop 每张 Bill
      Action->>DB: 2. 建 CollectionOrderBill(allocated=bill.amount)
      Action->>DB: 3. Bill.paid_amount = amount, status=Paid
    end

    Action->>Listener: 4. 触发 CollectionOrderCompleted
    Listener->>DB: 5. 建 Receipt(line_items × 4)
    Action->>DB: 提交事务

    Filament-->>业务: 成功通知
    业务-->>业户: 收据(含 4 项明细)

数据示例

收款后:

CollectionOrder(1 条)

id: 67890
collection_type: Bill
actual_amount: +1052
payment_channel: 微信
status: Completed
meta.fund_source: external

CollectionOrderBill(4 条)

collection_order_id bill_id allocated_amount
67890 物业费 Bill 800
67890 水费 Bill 54
67890 电费 Bill 168
67890 燃气 Bill 30

Bill(4 条更新)

每张 paid_amount = amount,status = Paid。

Receipt(1 条,4 行明细)

collection_order_id: 67890
amount: +1052
line_items: [
  { 物业费(5月), 800 },
  { 水费(5月), 54 },
  { 电费(5月), 168 },
  { 燃气(5月), 30 },
]

与单张收款的对比

| 维度 | collect-payment-single | 批量(本场景) | |---|---|---| | Modal 选账单 | 1 张(从 ViewBill 进入)| 多张(Table 勾选)| | CollectionOrder | 1 个 | 1 个(共用)| | CollectionOrderBill | 1 个 | N 个(每张一个)| | 业务人员操作 | 单笔 | 一笔 | | 业户体验 | 一张一张付(慢)| 一次付清(快)|

批量收款的好处:业户体验更好(一次付),业务人员工作量更小。唯一前提:业户愿意一次付清。

不同支付方式的分摊

业户支付的钱自动按账单原金额比例分摊 到各 Bill。不需要业务人员手动分配。

例:¥1,052 微信付 → 4 个 CollectionOrderBill 各自 allocated_amount = 该账单 amount(全额分配)。

如果业户付不够(部分批量付)

业户只想付 ¥600(不够 ¥1,052)→ 业务人员有几种选择:

策略 操作
优先付物业费(默认?) ¥600 全部分配给物业费 Bill(部分付)
按比例分摊 600 × 800/1052 = 456 给物业费,600 × 54/1052 = 31 给水费, ...
业务人员手动决定 给业务人员选哪张账单付多少

当前实现的具体策略看代码。业务上建议优先付到期早的(避免逾期)。

[!info] 批量收款的"部分付"复杂度 上述场景比单张部分付更复杂。当前 BatchCollectPaymentAction 可能只支持全额批量(若金额够付所有选中账单 → 全付;不够 → 走单张部分付逐张操作)。看实现。

业务人员视角:Modal 的预检查

类似 smart-bulk-delete-design 的预检查思路:

  • 选中 4 张账单 → Modal 显示"总计 ¥1,052"
  • 选中包含已 Paid 的账单 → Modal 显示"4 选 + 1 已付跳过"
  • 选中包含 Suspended → Modal 提示 "该账单挂起,无法收款"

[!info] 当前实现的成熟度 BatchCollectPaymentAction 的智能 Modal 程度看实现。可能比 BulkDeleteBillsAction 简单(批删有 issue.md Q6 详细设计,批收款未单独描述)。

常见问题

[!question] 选中跨业户的多张账单能批量收款吗? 业务上不应该(不同业户付的钱不能混)。系统层面应校验同业户,否则拒绝。

例外:家属代付场景(儿子来付父母账单)→ 业务上算同业户的钱。

[!question] 批量收款失败一半怎么办? 事务内全成功或全失败。任一 Bill 校验失败(例如某张已 Paid)→ 整笔回滚 → 业户的钱不被收。

实施上可能优化为"部分成功"(只失败的跳过),但破坏事务原子性,通常不推荐。

[!question] 业户支付的钱比账单合计? Modal 守护应限制金额 ≤ 合计。如果业务上业户故意多给:

  • 找零给业户(系统层面只收账单的金额)
  • 或转入业户预存款账户(若有此自动逻辑)

[!question] 不同期次的账单能一起付吗? 可以(账单状态都是 Unpaid 即可)。例如付 4 月物业费 + 5 月物业费 + 5 月水电气。

[!question] 批量收款的 activitylog 怎么记? 一条 CollectionOrder 的 activitylog(event=created)+ 每张 Bill 状态变化的 log。可在 SQL 反查 affected_bill_ids。

异常分支

相关文档