Files
uniprop-manual/prop-acc/scenarios/prepaid/consume-multiple-bills-priority.md
2026-05-25 23:27:56 +08:00

6.9 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 · 场景 - 多个未付账单按 due_at 优先级抵扣
多账单抵扣优先级
优先抵最早到期账单
consume-multiple-bills-priority
场景-多账单优先级抵扣
场景
prop-acc
预存款
消费
业户
业务人员
已发布 prepaid 2026-05-25 2026-05-22

场景:多个未付账单按 due_at 优先级抵扣

业户某月有多张未付账单(物业费、水电费、电梯维护费等),余额需抵多张。优先抵最早到期的账单(避免逾期罚款)。本场景描述业务人员的批量抵扣逻辑,也是 auto-deduction-design 的核心算法。

典型情境

[!example] 真实情境 张阿姨家 5 月有 3 张未付账单:

账单 金额 due_at
5 月物业费 ¥800 5 月 15 日
5 月水电费 ¥1,200 5 月 20 日
Q2 电梯维护费 ¥300 5 月 31 日

合计 ¥2,300,张阿姨账户余额 ¥2,500。全部能抵,但顺序很重要:

  1. 物业费(5 月 15 日)— 最早到期,先抵
  2. 水电费(5 月 20 日)
  3. 电梯维护费(5 月 31 日)

抵完余 ¥200。

业户视角

您会感受到什么

  • 5 月底收到 3 张收据(各账单一张),金额对应原账单
  • 小程序"我的预存款"流水按抵扣时间倒序显示 3 笔 consume
  • 小程序"我的账单"3 张全部 Paid
  • 推送通知"5 月 3 张账单已抵扣,余额 ¥200"

您要做什么

什么都不用。看明白即可。

[!info] 余额够不够全付决定行为

  • 够全付:全部抵,余额剩下的留账户
  • 不够全付:按优先级先抵最早到期的,后面的留 Unpaid 状态 → 推送"余额不足,请充值"

业务人员视角

第 1 步:打开账户

后台 → 预存款 → 找到张阿姨账户 → 进 ViewPrepaidAccount(balance=2500)。

第 2 步:逐张抵扣(手动模式)

[!warning] 当前没有"一键全抵"按钮 业务人员需要对每张账单各点一次 ConsumeAction。这是 auto-deduction-design 要解决的痛点。

正确顺序(按 due_at 升序):

步骤 选 Bill 抵 amount 之后余额
1 5 月物业费(due 5/15) 800 2500 → 1700
2 5 月水电费(due 5/20) 1200 1700 → 500
3 Q2 电梯维护费(due 5/31) 300 500 → 200

每张账单走完整 consume-monthly-property-bill 流程(Modal → 提交 → 触发监听器 → Receipt)。

第 3 步:核对结果

  • 3 张账单全 Paid
  • 账户余额 ¥200
  • 3 张 Receipt 已生成(分别 ¥800 ¥1,200 ¥300)

优先级排序逻辑(自动 job 用)

未来自动 job 实现后,按以下顺序排序未付账单:

排序键 升序/降序 业务理由
1. due_at 升序 最早到期的先抵(避免逾期产生滞纳金 / 影响信用)
2. bill_type 自定义("物业费" → "水电费" → "其他") 物业费是核心服务费,优先
3. amount 升序 同优先级下,小额先抵清(避免余额不够时多张大账单都半抵)
4. created_at 升序 兜底:早建的先

伪代码:

unpaid_bills = sorted(
    bills,
    key=lambda b: (b.due_at, BILL_TYPE_ORDER[b.bill_type], b.amount, b.created_at)
)

balance = account.balance
for bill in unpaid_bills:
    if balance <= 0:
        break
    if balance >= bill.amount:
        consume(account, bill, bill.amount)
        balance -= bill.amount
    else:
        # 余额不够全付该账单 → 跳过,等业户充值
        notify(account.resident, "余额不足,无法抵 ¥{bill.amount}{bill.bill_type}")
        # 或部分抵(看 Bill 是否支持):consume(account, bill, balance); balance = 0; break

余额不够全付的策略对比

假设张阿姨账户余额 ¥1,500,3 张账单合计 ¥2,300:

策略 行为 结果
全部跳过 余额不够任何一笔不动 3 张全 Unpaid,余额 ¥1,500 闲置
按优先级抵到不够为止(推荐) 物业费 800 → 余 700;水电费 1200 不够跳过;电梯费 300 余 700 ≥ 300 → 抵 → 余 400 物业费 + 电梯费 Paid,水电费 Unpaid,余额 ¥400
按优先级抵 + 部分抵末张 物业费 800 → 余 700;水电费 1200 > 700 → 抵 700 部分 → 水电费余 500;电梯费 300 余 0 跳过 物业费 Paid + 水电费部分付 + 电梯费 Unpaid + 余额 0

推荐第二种(按优先级抵到不够为止,不做部分抵)。理由:

  • 简单,Bill 模块不用支持部分付
  • 业户看到余额还有钱但有账单未付,会主动充值
  • 避免"抵了一半"的复杂状态

第三种等 Bill 模块支持部分支付后再考虑。

系统流程(手动模式 3 笔操作)

sequenceDiagram
    participant 财务
    participant Filament
    participant Account
    participant 数据库

    Note over 财务: 余额 2500,3 张未付账单

    财务->>Filament: ConsumeAction(物业费 800)
    Filament->>Account: consume(物业费, 800)
    Account->>数据库: balance 2500→1700, Bill Paid

    财务->>Filament: ConsumeAction(水电费 1200)
    Filament->>Account: consume(水电费, 1200)
    Account->>数据库: balance 1700→500, Bill Paid

    财务->>Filament: ConsumeAction(电梯费 300)
    Filament->>Account: consume(电梯费, 300)
    Account->>数据库: balance 500→200, Bill Paid

    Note over 数据库: 3 张账单 Paid + 3 张 Receipt + 余额 200

常见问题

[!question] 业务人员漏抵某张账单怎么办? 单纯漏抵 → 后续发现再抵一次。如果业户因此被收滞纳金,物业可走 ../adhoc/cancel-amount-error-redo 之类的补救路径。

[!question] 业务人员抵错优先级(先抵晚到期的)? 不影响资金正确性(账户余额扣对了,账单状态更新对了)。业务上可能让早到期的账单进入逾期。预防 = 培训业务人员看 due_at,根治 = 上自动 job。

[!question] 跨多个业户批量抵扣可以吗? 当前不行,只能一个账户一个账户操作。批量是自动 job 的核心需求

[!question] 业务人员选错账单(选了别人的)? Modal 的账单下拉已经过滤同业户 + 同社区,理论上选不到别人的。除非 UI / 数据有 bug,否则不会发生。

[!question] 部分抵扣场景频繁吗? 业务上罕见 —— 业户通常一次充够覆盖几个月。如果某业户经常余额不够,业务人员应主动提醒"建议充够 3 个月"。

异常分支

相关文档