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 优先级抵扣 |
|
|
|
已发布 | 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。全部能抵,但顺序很重要:
- 物业费(5 月 15 日)— 最早到期,先抵
- 水电费(5 月 20 日)
- 电梯维护费(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 个月"。
异常分支
- 单笔抵扣 → consume-monthly-property-bill
- 计量类账单(水电费)→ consume-meter-bill
- 余额不够 → 告知业户充值
- 月初批量(未来)→ consume-batch-auto-monthly
- 账户冻结 → unfreeze-after-verification