Compare commits

..

2 Commits

Author SHA1 Message Date
Willie
a98bdaf98e deposit 子模块 · 轮 2:18 场景 + 知识地图收尾
写 18 个场景到 prop-acc/scenarios/deposit/,覆盖 7 类业务:

📥 缴纳(3):
- deposit-first-time-renovation(张阿姨首次缴 5000)
- deposit-additional-topup(陈先生追加 2000)
- deposit-on-behalf-by-company(王装修代 3 户业主缴 15000)

💰 退款(3):
- refund-full-no-damage(无损全退)
- refund-partial-after-forfeit(扣 800 退 4200)
- refund-with-payment-channel-switch(现金缴 → 银行转账退)

⚠️ 扣罚(2):
- forfeit-damage-public-area(墙面损坏扣 800)
- forfeit-violation-no-permit(未报备私自动工违约扣 3000)

🧊 冻结/解冻(2):
- freeze-during-dispute(纠纷期间冻结)
- unfreeze-after-mediation(调解后解冻)

🔒 结清(2):
- close-after-zero-balance(余额清零自动 Closed)
- close-manual-with-zero-balance(主动关空账户)

🚨 强制关账(3,Frozen + 有余额困境):
- force-close-refund(全退,鉴定无责)
- force-close-forfeit(全扣,仲裁全责)
- force-close-retain(资金保留,业户失联/装修方倒闭)

🛡️ 异常/审计(3):
- exception-deposit-on-frozen(冻结状态尝试缴款被三层守护拦截)
- audit-monthly-deposit-balance(月度三方对账:账面 == 银行专户 == 流水净值)
- audit-long-pending-accounts(超 2 年未关账户分类清理)

每篇结构:典型情境 → 业户视角 → 业务人员视角 → 系统流程(mermaid)→
流水台账 → 常见问题 → 异常分支 → 相关文档。

收尾:
- prop-acc/maps/deposit-knowledge-map.md:18 场景全部 ,加完成 callout
- prop-acc/maps/knowledge-map.md:deposit 行状态改 " 25 篇"
- prop-acc/index.md:同步

deposit 子模块完整覆盖:6 概念 + 18 场景 + 1 知识地图 = 25 篇。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 22:40:19 +08:00
Willie
29938ecbe0 vault backup: 2026-05-25 22:37:41 2026-05-25 22:37:41 +08:00
9 changed files with 1033 additions and 30 deletions

View File

@@ -196,6 +196,10 @@
}, },
"active": "b06ed69835363258", "active": "b06ed69835363258",
"lastOpenFiles": [ "lastOpenFiles": [
"prop-acc/scenarios/deposit/audit-monthly-deposit-balance.md",
"prop-acc/scenarios/deposit/exception-deposit-on-frozen.md",
"prop-acc/scenarios/deposit/force-close-retain.md",
"prop-acc/scenarios/deposit/force-close-forfeit.md",
"prop-acc/scenarios/deposit/force-close-refund.md", "prop-acc/scenarios/deposit/force-close-refund.md",
"prop-acc/scenarios/deposit/close-manual-with-zero-balance.md", "prop-acc/scenarios/deposit/close-manual-with-zero-balance.md",
"prop-acc/scenarios/deposit/close-after-zero-balance.md", "prop-acc/scenarios/deposit/close-after-zero-balance.md",
@@ -220,10 +224,6 @@
"prop-acc/concepts/deposit/account-state-machine.md", "prop-acc/concepts/deposit/account-state-machine.md",
"prop-acc/concepts/deposit/deposit-account-vs-transaction.md", "prop-acc/concepts/deposit/deposit-account-vs-transaction.md",
"prop-acc/concepts/deposit", "prop-acc/concepts/deposit",
"prop-acc/maps/adhoc-knowledge-map.md",
"prop-acc/scenarios/adhoc/cancel-resident-withdrawal.md",
"prop-acc/scenarios/adhoc/flow-a-counter-buy-ic-card.md",
"概念-CollectionOrder与Receipt.md",
"prop-acc/scenarios/adhoc", "prop-acc/scenarios/adhoc",
"prop-acc/concepts/adhoc", "prop-acc/concepts/adhoc",
"resident-portal/scenarios", "resident-portal/scenarios",

View File

@@ -24,7 +24,7 @@ last_review: 2026-05-25
| 子模块 | 一句话 | 深度地图 | 状态 | | 子模块 | 一句话 | 深度地图 | 状态 |
|---|---|---|---| |---|---|---|---|
| **一次性收费** | IC 卡、装修证、泳票等单次购买 | [adhoc 知识地图](maps/adhoc-knowledge-map.md) | ✅ 28 篇 | | **一次性收费** | IC 卡、装修证、泳票等单次购买 | [adhoc 知识地图](maps/adhoc-knowledge-map.md) | ✅ 28 篇 |
| **保证金** | 装修押金等代管资金,完工后退还 | [deposit 知识地图](maps/deposit-knowledge-map.md) | 🟡 6 概念已完成,18 场景待补 | | **保证金** | 装修押金等代管资金,完工后退还 | [deposit 知识地图](maps/deposit-knowledge-map.md) | ✅ 25 篇 |
| **预存款** | 业户预存,自动抵扣月度账单 | _待补_ | 🚧 | | **预存款** | 业户预存,自动抵扣月度账单 | _待补_ | 🚧 |
| **计量表** | 水表/电表/燃气表,抄表生成账单 | _待补_ | 🚧 | | **计量表** | 水表/电表/燃气表,抄表生成账单 | _待补_ | 🚧 |
| **账单** | 周期性账单 + 计量账单 | _待补_ | 🚧 | | **账单** | 周期性账单 + 计量账单 | _待补_ | 🚧 |

View File

@@ -43,50 +43,48 @@ code_version: 2026-05-22
| [红字凭证设计](../concepts/deposit/red-receipt-design.md) | 退款扣罚走红字 CollectionOrder + Receipt,而非新增枚举 | | [红字凭证设计](../concepts/deposit/red-receipt-design.md) | 退款扣罚走红字 CollectionOrder + Receipt,而非新增枚举 |
| [押金 vs 一次性收费 vs 预存款](../concepts/deposit/deposit-vs-adhoc-vs-prepaid.md) | 三个子模块的会计本质区别(收入 vs 预收 vs 代管) | | [押金 vs 一次性收费 vs 预存款](../concepts/deposit/deposit-vs-adhoc-vs-prepaid.md) | 三个子模块的会计本质区别(收入 vs 预收 vs 代管) |
## 场景手册(18 篇,**待补充 ✋**) ## 场景手册(18 篇,**全部完成 ✅**)
> 🚧 概念骨架已就位,场景文档将在下一轮产出。预定结构如下。
### 📥 缴纳(Deposit)— 3 篇 ### 📥 缴纳(Deposit)— 3 篇
- 🚧 [装修业户首次缴 5,000 保证金](../scenarios/deposit/deposit-first-time-renovation.md) - [装修业户首次缴 5,000 保证金](../scenarios/deposit/deposit-first-time-renovation.md)
- 🚧 [已有账户后续追加缴款](../scenarios/deposit/deposit-additional-topup.md) - [已有账户后续追加缴款](../scenarios/deposit/deposit-additional-topup.md)
- 🚧 [装修公司代业户缴纳](../scenarios/deposit/deposit-on-behalf-by-company.md) - [装修公司代业户缴纳](../scenarios/deposit/deposit-on-behalf-by-company.md)
### 💰 退款(Refund)— 3 篇 ### 💰 退款(Refund)— 3 篇
- 🚧 [装修完无损全额退还](../scenarios/deposit/refund-full-no-damage.md) - [装修完无损全额退还](../scenarios/deposit/refund-full-no-damage.md)
- 🚧 [部分扣罚后退还差额](../scenarios/deposit/refund-partial-after-forfeit.md) - [部分扣罚后退还差额](../scenarios/deposit/refund-partial-after-forfeit.md)
- 🚧 [退款渠道与缴款渠道不同](../scenarios/deposit/refund-with-payment-channel-switch.md) - [退款渠道与缴款渠道不同](../scenarios/deposit/refund-with-payment-channel-switch.md)
### ⚠️ 扣罚(Forfeiture)— 2 篇 ### ⚠️ 扣罚(Forfeiture)— 2 篇
- 🚧 [损坏公共走道墙面扣 800](../scenarios/deposit/forfeit-damage-public-area.md) - [损坏公共走道墙面扣 800](../scenarios/deposit/forfeit-damage-public-area.md)
- 🚧 [未申请直接动工违约扣罚](../scenarios/deposit/forfeit-violation-no-permit.md) - [未申请直接动工违约扣罚](../scenarios/deposit/forfeit-violation-no-permit.md)
### 🧊 冻结 / 解冻(Freeze / Unfreeze)— 2 篇 ### 🧊 冻结 / 解冻(Freeze / Unfreeze)— 2 篇
- 🚧 [业户纠纷期间冻结账户](../scenarios/deposit/freeze-during-dispute.md) - [业户纠纷期间冻结账户](../scenarios/deposit/freeze-during-dispute.md)
- 🚧 [调解结束后解冻](../scenarios/deposit/unfreeze-after-mediation.md) - [调解结束后解冻](../scenarios/deposit/unfreeze-after-mediation.md)
### 🔒 结清(Close)— 2 篇 ### 🔒 结清(Close)— 2 篇
- 🚧 [余额清零自动关闭](../scenarios/deposit/close-after-zero-balance.md) - [余额清零自动关闭](../scenarios/deposit/close-after-zero-balance.md)
- 🚧 [主动关账(已无业务往来)](../scenarios/deposit/close-manual-with-zero-balance.md) - [主动关账(已无业务往来)](../scenarios/deposit/close-manual-with-zero-balance.md)
### 🚨 强制关账(ForceClose)— 3 篇 ### 🚨 强制关账(ForceClose)— 3 篇
> 解决 "Frozen + 有余额 + 想关账" 的设计困境。三种 disposition 对应不同业务出口。 > 解决 "Frozen + 有余额 + 想关账" 的设计困境。三种 disposition 对应不同业务出口。
- 🚧 [冻结状态强制全退并关账](../scenarios/deposit/force-close-refund.md) - [冻结状态强制全退并关账](../scenarios/deposit/force-close-refund.md)
- 🚧 [冻结状态强制全扣并关账](../scenarios/deposit/force-close-forfeit.md) - [冻结状态强制全扣并关账](../scenarios/deposit/force-close-forfeit.md)
- 🚧 [法律保留期 / 业户失联,资金保留并关账](../scenarios/deposit/force-close-retain.md) - [法律保留期 / 业户失联,资金保留并关账](../scenarios/deposit/force-close-retain.md)
### 🛡️ 异常 / 审计 / 配置 — 3 篇 ### 🛡️ 异常 / 审计 / 配置 — 3 篇
- 🚧 [冻结账户尝试缴款被守护拦截](../scenarios/deposit/exception-deposit-on-frozen.md) - [冻结账户尝试缴款被守护拦截](../scenarios/deposit/exception-deposit-on-frozen.md)
- 🚧 [月度押金账户余额对账](../scenarios/deposit/audit-monthly-deposit-balance.md) - [月度押金账户余额对账](../scenarios/deposit/audit-monthly-deposit-balance.md)
- 🚧 [长期未关账户排查](../scenarios/deposit/audit-long-pending-accounts.md) - [长期未关账户排查](../scenarios/deposit/audit-long-pending-accounts.md)
## 跨域引用 ## 跨域引用
@@ -120,6 +118,9 @@ code_version: 2026-05-22
--- ---
> [!info] 概念已完成,场景待补 > [!success] deposit 子模块:6 概念 + 18 场景 + 1 知识地图 = **25 篇完成**
> 本轮(轮 1)产出:6 个概念 + 本子模块地图 + 域总图更新。 >
> 下一轮(轮 2)产出:18 个场景文档,基于本知识地图骨架填充。 > 写作日期:2026-05-25
> 对应代码版本:2026-05-22(详见 `packages/prop-acc/issue.md` Q3 段)
>
> 如果发现遗漏的场景或需要补充的细节,告诉我,可以单独补充新文档。

View File

@@ -21,7 +21,7 @@ last_review: 2026-05-25
|---|---|---|---|---| |---|---|---|---|---|
| adhoc | 一次性收费 | IC 卡、装修证、泳票等单次购买 | [adhoc 知识地图](adhoc-knowledge-map.md) | ✅ 25 场景 + 3 概念 | | adhoc | 一次性收费 | IC 卡、装修证、泳票等单次购买 | [adhoc 知识地图](adhoc-knowledge-map.md) | ✅ 25 场景 + 3 概念 |
| prepaid | 预存款 | 业户预存,自动抵扣月度账单 | _待补_ | 🚧 | | prepaid | 预存款 | 业户预存,自动抵扣月度账单 | _待补_ | 🚧 |
| deposit | 保证金 | 装修押金等代管资金,完工后退还 | [deposit 知识地图](deposit-knowledge-map.md) | 🟡 6 概念已完成,18 场景待补 | | deposit | 保证金 | 装修押金等代管资金,完工后退还 | [deposit 知识地图](deposit-knowledge-map.md) | ✅ 18 场景 + 6 概念 + 1 地图 = 25 篇 |
| meter | 计量表 | 水表/电表/燃气表,抄表生成账单 | _待补_ | 🚧 | | meter | 计量表 | 水表/电表/燃气表,抄表生成账单 | _待补_ | 🚧 |
| billing | 账单 | 周期性账单 + 计量账单 | _待补_ | 🚧 | | billing | 账单 | 周期性账单 + 计量账单 | _待补_ | 🚧 |
| payment-order | 收款订单 | 一次收款的支付方式、银行账户记录 | _待补_ | 🚧 | | payment-order | 收款订单 | 一次收款的支付方式、银行账户记录 | _待补_ | 🚧 |

View File

@@ -0,0 +1,186 @@
---
title: prop-acc · deposit · 场景 - 长期未关账户排查
aliases:
- 长期未关账户
- 押金账户清理
- audit-long-pending-accounts
- 场景-长期押金账户排查
tags:
- 场景
- prop-acc
- 保证金
- 审计
audience:
- 财务
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:长期未关账户排查
物业财务**季度 / 半年**做一次扫描,找出**开户时间过长但仍未关账**的账户,逐个调查原因并推进结清。是合规要求,避免代管负债无限累积。
## 典型情境
> [!example] 真实情境
> 物业财务王主管在 2026 年中做"超 2 年未关押金账户"清理:
>
> - 系统里查出 23 个账户开户时间超过 2 年,状态仍 Active
> - 其中 18 个是装修早已结束但物业 / 业户都忘了走退款流程
> - 4 个是业户已搬走联系不上
> - 1 个是因为业户提出物业服务费纠纷,押金账户被业户作为"筹码"
>
> 主管要逐个推进:能联系的发起退款、联系不上的走 retain、纠纷的走 freeze。
## 业务人员视角
### 第 1 步:扫描出长期账户
```sql
-- 开户超 2 年仍 Active 的账户
SELECT
id,
payer_name,
payer_contact,
balance,
status,
opened_at,
TIMESTAMPDIFF(MONTH, opened_at, NOW()) AS months_open,
community_id,
asset_id,
community_user_profile_id
FROM acc_deposit_accounts
WHERE status IN ('active', 'frozen')
AND opened_at < NOW() - INTERVAL 2 YEAR
ORDER BY opened_at ASC;
```
也可按需要调整阈值:1 年 / 6 个月 / 3 个月。装修押金正常应在 3-6 个月内结清,超过 1 年就异常。
### 第 2 步:分类并定调处理路径
| 类型 | 表现 | 处理路径 |
|---|---|---|
| **A. 装修早已结束,忘了退** | 装修施工证已过期、业户已正常入住 | 主动联系业户 → 走 [[refund-full-no-damage]] |
| **B. 业户失联** | 联系方式打不通、上门无人 | 等失联期到法律保留期 → [[force-close-retain]] |
| **C. 装修方已倒闭(三方账户)** | 公司账户、付款人已注销 | 走法律程序 + [[force-close-retain]] |
| **D. 业户与物业有纠纷** | 业户用押金作筹码 | [[freeze-during-dispute]] 冻结 → 调解 |
| **E. 数据问题(开账户没缴款)** | balance=0 但状态仍 Active | [[close-manual-with-zero-balance|主动关账]] |
| **F. 装修中(正常)** | 施工合同仍有效、近期有缴款 / 扣罚动作 | 不动 |
### 第 3 步:逐个推进
对每条记录:
1.`ViewDepositAccount` 看流水台账(最后一次操作是什么时候、是什么)
2. 查业户联系方式 + 上次联系记录
3. 决定处理路径
4. 执行(走对应场景)
5. 在内部清理 Excel 记录"已处理:[路径],日期:[XX-XX-XX]"
### 第 4 步:出报告
```markdown
# 2026 年 Q2 超 2 年未关押金账户清理报告
## 总数:23
- A. 退款关账(联系业户成功):16
- B. 资金保留(联系不上):4
- C. 已 freeze 进入调解:1
- D. 主动关账(数据异常):2
## 资金处置
- 退款总额:¥85,400
- retain 总额:¥18,200(进入"待业户领取"清单)
- 仍 Active(纠纷调解中):¥5,000
## 后续动作
- retain 4 户:每年节点扫描,业户出现立即处理
- freeze 1 户:跟进调解
- 建议:开户超过 12 个月物业管家主动跟进("您家装修是否结束?")
```
## 系统流程
```mermaid
flowchart TD
A[季度/半年触发] --> B[运行 SQL 扫描长期账户]
B --> C[人工分类]
C --> D[A. 联系业户成功<br/>→ refund-full-no-damage]
C --> E[B. 业户失联<br/>→ force-close-retain]
C --> F[C. 装修方倒闭<br/>→ force-close-retain + 法务]
C --> G[D. 业户纠纷<br/>→ freeze-during-dispute]
C --> H[E. 数据异常 balance=0<br/>→ close-manual-with-zero-balance]
C --> I[F. 正常装修中<br/>→ 不动]
D --> J[出清理报告]
E --> J
F --> J
G --> J
H --> J
```
## 常见问题
> [!question] 为什么要做这种清理?
> 几个理由:
>
> - **合规**:代管负债不应无限累积。账面挂着却没业务对应的押金,审计会问"这笔钱凭什么还在你这"
> - **资金占用**:这些押金占用专户额度,物业不能用,但也算合规成本
> - **追溯困难**:超 5 年的账户对应的业务人员、装修方都可能不在了,处理起来更难
> - **风险积累**:业户某天突然要求退款,如果联系不上当年的相关人 / 凭证,物业会很被动
> [!question] 开户多久算"长期"?
> 取决于业务:
> - **装修押金**:超 6 个月就开始关注,超 12 个月主动联系,超 24 个月强制处理
> - **入驻押金 / 设备押金**:可能合理保留多年,看合同期
> - **保留(retain)账户**:理论上随时可被业户领回,无时间限制
>
> 各物业自行设阈值,SQL 查询调整 `INTERVAL` 即可。
> [!question] 长期账户找业户但业户拒接 / 无回应,算失联吗?
> 一般做法:
> - 物业管家上门 3 次 + 短信 3 次 + 电话 5 次,均无回应 → 视为失联
> - 留**书面记录**(每次联系尝试的日期、方式、结果)
> - 满足"已尽合理联系义务"的法律标准
> - 然后走 [[force-close-retain|资金保留]]
>
> 直接 ForceClose retain 没问题,但建议先 [[freeze-during-dispute|冻结]] 等一段时间(例如 30 天),给业户最后机会。
> [!question] retain 的资金最终怎么变成"非负债"?
> 各地法规不同,但通常:
> - 长期无主资金(5-10 年以上),走司法程序判归
> - 街道办 / 民政部门接管
> - 部分地区可转入物业自有资金(需特别审批)
>
> 走完这些流程后,在该 retain 账户 meta 加 `transferred_to_*` 字段记录归属,**但账户本身仍 Closed**(不重启)。账面上的资金责任随转出而清。
> [!question] 这个扫描应该自动化吗?
> 可以,但**不推荐自动执行操作**:
> - 自动 SQL 扫描可定时跑,生成报告
> - **任何账户状态变更必须人工触发** —— 不能让定时任务自动 forceClose
> - 自动操作 = 没人对结果负责 = 出错没人查
> [!question] 报告做完没人处理怎么办?
> 这是物业内部管理问题,不是系统问题。建议:
> - 报告产生 = OKR 指标(财务团队 KPI)
> - 上报物业总经理 + 法务,纳入月度运营回顾
> - 长期堆积的报告 = 内控失效的信号
## 异常分支
- 找出大批"无缴款"账户 → 业务流程可能有缺陷,改"业户开始装修当天才开户"流程
- 找出疑似挪用资金的账户 → 法务 + 内部审计介入
- retain 账户的余额合计很大(影响财务报表)→ 设单独"代管资金 - 待处置"科目
## 相关文档
- [[audit-monthly-deposit-balance]]
- [[force-close-retain]]
- [[refund-full-no-damage]]
- [[freeze-during-dispute]]
- [[close-manual-with-zero-balance]]

View File

@@ -0,0 +1,241 @@
---
title: prop-acc · deposit · 场景 - 月度押金账户余额对账
aliases:
- 押金月对账
- 押金账面与银行对账
- audit-monthly-deposit-balance
- 场景-押金月度对账
tags:
- 场景
- prop-acc
- 保证金
- 审计
audience:
- 财务
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:月度押金账户余额对账
物业财务**每月底**对所有押金账户做一次余额校验,确保系统账面 = 银行专户余额 = 流水累计净值,三方平衡。是审计内控的标准动作。
## 典型情境
> [!example] 真实情境
> 物业财务王主管每月最后一个工作日做"押金账户余额三方对账":
>
> 1. 系统所有 Active + Closed-retain 账户的 `balance` + `meta.balance_held_amount` 之和
> 2. 银行"装修押金专户"的实际余额
> 3. 全部 `DepositTransaction` 按净值累加 + retain 保留金额
>
> 三者必须**完全相等**,任何差额都要查清。
## 三方对账详解
### 1. 系统账面余额(System Balance)
```sql
-- Active 账户的当前余额
SELECT SUM(balance) FROM acc_deposit_accounts WHERE status = 'active';
-- + Frozen 账户的当前余额(冻结期间余额仍属业户)
SELECT SUM(balance) FROM acc_deposit_accounts WHERE status = 'frozen';
-- + Closed 但保留资金的账户(retain disposition)
SELECT SUM(JSON_EXTRACT(meta, '$.balance_held_amount'))
FROM acc_deposit_accounts
WHERE status = 'closed' AND JSON_EXTRACT(meta, '$.force_closed_disposition') = 'retain';
```
三者之和 = **物业代管负债总额**
### 2. 银行专户余额(Bank Balance)
物业的"装修押金银行专户"(单独开立的隔离账户)的月底余额。
> [!info] 为什么要专户隔离
> 押金是代管资金,**不应与物业自有资金混同**。专户的好处:
> - 内控明确,资金不被挪用
> - 对账简单(银行余额 == 应付业户的钱)
> - 监管合规(部分地区物业法规要求)
### 3. 流水累计净值(Transaction Sum)
```sql
-- 全部 DepositTransaction 的净值(deposit 加,refund/forfeiture 减)
SELECT
SUM(CASE WHEN type = 'deposit' THEN amount ELSE -amount END) AS net_balance
FROM acc_deposit_transactions;
-- 这个值理论上 == 所有 Active + Frozen 账户的 balance 之和
-- (不包括 retain Closed 账户,因为它们的 balance 字段未变,但已不在 Transaction 累加范围内 —— 实际上也累加了,因为 forfeiture/refund 没发生)
```
> [!info] 完整公式
> ```
> SUM(transactions 净值) = SUM(active.balance) + SUM(frozen.balance) + SUM(closed.balance where status=closed and balance>0)
> ```
> 任何不一致 → 有 bug 或人为绕过(详见 [[deposit-account-vs-transaction]] "两者的契约")。
### 三方平衡的预期
```
系统账面余额 == 银行专户余额 == 流水累计净值
```
任何一对不等 → 调查。
## 业务人员视角(月底操作)
### 第 1 步:导出系统账面余额报表
后台 → 保证金 → 列表 → 按"状态 Active / Frozen / Closed-retain"过滤 → 导出 Excel,合计 `balance` 列 + `meta.balance_held_amount` 列。
(或运行 SQL 查询,见上方)
### 第 2 步:取银行专户对账单
- 登录银行网银 / 联系银行客户经理
- 取本月最后一天的余额(精确到分)
### 第 3 步:做对账
| 维度 | 数值 | 来源 |
|---|---|---|
| A. 系统账面余额 | ¥X | 后台导出 |
| B. 银行专户余额 | ¥Y | 银行对账单 |
| C. 流水累计净值 | ¥Z | SQL 查询 |
| **差额(应 0)** | A - B 和 A - C | |
如果三个值不相等,**这才是对账的核心工作**:查清差异。
### 第 4 步:差额排查
常见差异原因:
| 差异 | 可能原因 | 排查方法 |
|---|---|---|
| A > B(系统多于银行) | 账面收了但银行未到账(在途资金) | 查最近 deposit 的支付渠道(POS / 微信)是否回滚 |
| A < B(系统少于银行) | 银行多了钱但系统没记(混账)| 查银行流水那笔多的钱来源 |
| A ≠ C(系统账面与流水不一致)| 系统 bug 或 tinker 改过余额 | `$account->verifyBalance()` 找出哪个账户不一致 |
> [!warning] 任何不一致都是事故
> 即使差额很小(¥1),也必须查清。押金是负债 = 业户的钱,任何不平都是合规风险。
### 第 5 步:出对账报告
格式:
```markdown
# 2026 年 5 月 装修押金账户对账报告
## 三方余额
- 系统账面:¥152,300.00(Active 89 + Frozen 3 + Retain 4)
- 银行专户:¥152,300.00
- 流水净值:¥152,300.00
## 平衡情况:✅ 完全平衡
## 本月新增账户:12
## 本月关账:8(其中 retain 1)
## 本月扣罚 / 退款总额:¥85,400 / ¥73,200
```
如有差异:
```markdown
## ⚠️ 差异
- 系统账面 ¥X 与银行 ¥Y 差 ¥Z
- 已查:第 N 笔 deposit on 2026-05-22 的微信支付实际未到账(支付平台冻结审核)
- 处理:待 5-28 微信渠道放款,再次对账确认
## 本月需复盘
- ID 4567 账户余额异常:`verifyBalance()` 返 false,差 ¥0.5(疑似浮点误差或人为编辑)
- 已 tinker 修复 + 加备注
```
## 系统流程
```mermaid
flowchart TD
A[月底触发] --> B[导出系统账面]
A --> C[取银行专户对账单]
A --> D[查询流水累计]
B --> E{三方相等?}
C --> E
D --> E
E -- 是 --> F[出对账报告 ✅]
E -- 否 --> G[排查差异]
G --> H[追溯交易 / 查 verifyBalance / 排查 tinker 操作]
H --> I[修复 + 备注]
I --> J[重新对账]
J --> E
```
## 报表 SQL 汇总(供财务复用)
```sql
-- 本月新增账户
SELECT COUNT(*) FROM acc_deposit_accounts
WHERE created_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59';
-- 本月关账(含自动关账 + 主动关账 + ForceClose)
SELECT COUNT(*),
COUNT(*) FILTER (WHERE JSON_EXTRACT(meta, '$.force_closed_disposition') IS NOT NULL) AS force_closed,
COUNT(*) FILTER (WHERE JSON_EXTRACT(meta, '$.force_closed_disposition') = 'retain') AS retain_count
FROM acc_deposit_accounts
WHERE status = 'closed'
AND updated_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59';
-- 本月扣罚总额
SELECT SUM(amount) FROM acc_deposit_transactions
WHERE type = 'forfeiture'
AND created_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59';
-- 本月退款总额
SELECT SUM(amount) FROM acc_deposit_transactions
WHERE type = 'refund'
AND created_at BETWEEN '2026-05-01' AND '2026-05-31 23:59:59';
```
## 常见问题
> [!question] 没有银行专户怎么对账?
> 退一步,与物业总账户对账,但只能看"已收 / 已退"流水净值,**无法判断资金是否被挪用**(被混入其他业务用资金池)。**强烈建议设置专户**。
> [!question] retain 账户的资金算物业代管负债吗?
> **算**。即使账户 Closed,只要 `meta.balance_held_amount > 0`,资金法律上仍属业户,会计上仍是"其他应付款"。详见 [[force-close-retain]]。
> [!question] 月度对账要审计师参与吗?
> 内部对账物业财务自己做。**年度审计**时审计师会重点检查这部分(物业的代管资金合规性、是否有挪用迹象)。月度对账留下完整记录是年审顺利的前提。
> [!question] 差额查不出来怎么办?
> 上报物业财务总监 + 法务。可能需要:
> - 委托第三方审计核对
> - 银行流水逐笔重对
> - tinker 操作日志审查(谁改了什么)
>
> **不能放任**,押金对账差异是严重合规问题。
> [!question] 多个物业项目的押金一起对吗?
> 通常每个 `community_id` 独立对账(每个物业项目一个银行专户)。系统层面也可按 community 分组导出。
## 异常分支
- 发现 `verifyBalance()=false` 的账户 → tinker 修复 + 排查根因
- 发现银行专户少于账面 → 资金挪用嫌疑,法务介入
- 发现长期 retain 的资金对应不上 → [[audit-long-pending-accounts|长期账户排查]]
## 相关文档
- [[deposit-account-vs-transaction]]
- [[transaction-types]]
- [[force-close-retain]]
- [[audit-long-pending-accounts]]
- [[deposit-vs-adhoc-vs-prepaid]]

View File

@@ -0,0 +1,175 @@
---
title: prop-acc · deposit · 场景 - 冻结账户尝试缴款被拦截
aliases:
- 冻结账户缴款被拒
- exception-deposit-on-frozen
- 场景-冻结账户缴款异常
tags:
- 场景
- prop-acc
- 保证金
- 异常
audience:
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:冻结账户尝试缴款被拦截
业务人员**误对一个 Frozen 账户**点击"追加缴款"按钮,系统按 [[account-state-machine|状态机]] 守护**直接拦截**,不让任何资金进入。
## 典型情境
> [!example] 真实情境
> 物业职员小李在前台办业户陈先生的押金追加业务。陈先生说"我再补 ¥1,000"。小李没注意到陈先生的账户当前处于 **Frozen 状态**(因之前墙面损坏纠纷),习惯性打开账户点了"追加缴款"按钮。
>
> 系统提示:**"账户处于冻结状态,无法缴款"**,操作被拒绝。
## 业务人员视角
### 您看到什么
| 时刻 | 看到 |
|---|---|
| 进入 `ViewDepositAccount` | 状态栏显示 "🧊 Frozen" |
| 状态管理组里的按钮 | "追加缴款 / 退款 / 扣罚" 全部**灰化**,只有 "Unfreeze / ForceClose" 可点 |
| 如果硬调 API | 系统抛出 `RuntimeException`:"账户处于冻结状态,canDeposit returns false" |
> [!info] 三道防御
> 1. **UI 层**:按钮根据 `canDeposit()` 状态自动灰化
> 2. **Policy 层**:`DepositAccountPolicy::update()` + 状态检查
> 3. **业务 Action 层**:`DepositIntoAccountAction` 入口校验 `canDeposit()`,失败抛异常
>
> 即使前两道被绕过(直接调 API、tinker 操作),第三道仍兜底。
### 第 1 步:看到操作被拒,理解原因
提示框信息:**"账户处于冻结状态,canDeposit returns false"**(系统消息 + 业务消息)。
### 第 2 步:与业户沟通
不要硬要绕过。说明:
> "您的账户当前因纠纷冻结,需先调解完成解冻后才能继续缴款。"
业户的几个可能反应:
| 业户反应 | 处理 |
|---|---|
| "那快帮我解冻" | 看是否有调解结果。无书面凭证不解冻 |
| "我先把钱给你,等解冻再录" | **不要这么做**。物业不能"暂存"业户的钱 —— 没有凭证 = 不合规。让业户先离开,等解冻 |
| "那这账户先不动了" | OK,告诉业户冻结期间状态、预计解冻时间 |
### 第 3 步:正确流程
1. 调解 → 拿到书面调解协议
2. [[unfreeze-after-mediation|解冻]] → 账户变 Active
3. [[deposit-additional-topup|追加缴款]] → 正常缴款流程
## 系统视角:守护链路
```mermaid
sequenceDiagram
participant 职员
participant Filament
participant DepositIntoAccountAction
participant DepositAccount
职员->>Filament: 点击"追加缴款" → DepositAction modal
Note over Filament: UI 守护:Frozen 状态按钮已灰化(防误点)
职员->>Filament: 如果绕过 UI,直接提交
Filament->>DepositIntoAccountAction: handle(account, amount)
DepositIntoAccountAction->>DepositAccount: canDeposit()?
DepositAccount-->>DepositIntoAccountAction: false (status=Frozen)
DepositIntoAccountAction-->>Filament: throw RuntimeException
Filament-->>职员: 显示错误:"账户处于冻结状态,无法缴款"
Note over 职员: 不会建任何 CO/Transaction/Receipt
```
## 为什么这条守护比直觉更严
历史上曾经的代码允许 `[Active, Frozen]` 都能缴款,直觉上"反正多存钱不亏",收紧成只允许 Active 是经过教训的。详见 [[account-state-machine]] "关键守护:Frozen 不允许任何资金动作" 段。
真实风险:
| 反例 | 后果 |
|---|---|
| 装修公司持续往受冻结的押金账户灌钱 | 资金被困、责任更复杂(冻结期间是否构成新债权?) |
| 业户与物业纠纷期间业户继续存钱 | 资金混同,扣罚 / 退款时算不清"哪一笔是原押金、哪一笔是纠纷后存的" |
| 系统给"暂存"开口子 | 业务人员可能用它做不规范操作("先放着,以后调整") |
收紧后**所有冻结期间的资金问题都必须先解冻**,语义清晰、审计可追。
## 测试断言
代码层有专门测试覆盖此异常路径:
```php
test('cannot deposit on frozen account', function () {
$account = DepositAccount::factory()->frozen()->create(['balance' => 5000]);
expect(fn () => app(DepositIntoAccountAction::class)->handle($account, 1000))
->toThrow(RuntimeException::class, '账户处于冻结状态');
expect($account->fresh()->balance)->toBe(5000.0); // 余额未变
expect(DepositTransaction::count())->toBe(0); // 流水未建
});
```
任何对 `canDeposit()` 的修改都会触发此测试,确保守护不被无意中放宽。
## 常见问题
> [!question] 业户坚持要存钱,职员怎么办?
> 解释 + 引导:
> - 解释为什么不能存(冻结期间所有资金动作禁止,无论方向)
> - 引导先完成调解 / 解冻
> - 如果业户着急,加快内部调解流程(联系物业管家)
> [!question] 业户已经把钱转过来了(对公转账已到账)但账户冻结,怎么办?
> 这是**业务问题**,不是系统问题:
> - 物业账户已收到这笔钱,但**不能挂在该业户的 DepositAccount 上**(冻结不允许)
> - 选项:
> - 退回业户(原路退,清晰)
> - 系统外暂留(物业银行账户里的"挂账" / 财务备查)
> - 等解冻后再录入
> - **推荐第一个**(退回业户),最干净
> [!question] 同样的守护对 ForceClose 适用吗?
> ForceClose 走**独立的 Policy 方法** `forceClose()`,守护是 `isFrozen() && hasBalance()` —— 这是**专门**为 Frozen 状态设计的,与 deposit / refund / forfeit 守护刚好"互补":
>
> | 守护 | 适用状态 | 阻止 |
> |---|---|---|
> | `canDeposit()` | Active only | Frozen / Closed 缴款 |
> | `canWithdraw()` | Active only | Frozen / Closed 退款 / 扣罚 |
> | `forceClose()` Policy | Frozen + hasBalance only | Active / Closed / Frozen-zero-balance 强制关账 |
>
> 这条对应详见 [[account-state-machine]]。
> [!question] 这个守护影响小程序业户自助操作吗?
> 当前没有小程序自助缴款 —— Action 假设手工操作。**未来加小程序在线缴款时**:
> - 前端调同一个 `DepositIntoAccountAction`,守护自动生效
> - 业户在小程序操作冻结账户时同样被拦截
> - UI 应在小程序侧显示更友好的错误信息(避免裸抛 RuntimeException 给业户)
> [!question] 怎么手工验证某账户是否 Frozen?
> 后台 → 保证金 → 列表 → 状态列;或 tinker `DepositAccount::find($id)->status`。
## 异常分支
- 想加缴款 → 先 [[unfreeze-after-mediation|解冻]] → [[deposit-additional-topup|追加]]
- 想退款 → 同上,或 [[force-close-refund|强制关账退还]]
- 想扣罚 → 同上,或 [[force-close-forfeit|强制关账扣罚]]
- 长期冻结无解 → [[force-close-retain|资金保留关账]]
## 相关文档
- [[account-state-machine]]
- [[freeze-during-dispute]]
- [[deposit-additional-topup]]
- [[force-close-refund]]
- [[force-close-forfeit]]

View File

@@ -0,0 +1,170 @@
---
title: prop-acc · deposit · 场景 - 冻结状态强制全扣并关账
aliases:
- 强制全扣关账
- ForceClose forfeit
- force-close-forfeit
- 场景-冻结强制扣罚关账
tags:
- 场景
- prop-acc
- 保证金
- 强制关账
audience:
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:冻结状态强制全扣并关账
账户处于 **Frozen** 状态、**还有余额**,**纠纷结果明确利向物业**(损坏归责确认业户全责、违约严重、司法判决物业胜诉等)。物业用 `ForceCloseAction``forfeit` disposition,**一步完成"解冻 + 全额扣罚 + 关账"**。
## 典型情境
> [!example] 真实情境
> 刘先生家装修时**多次违反装修管理协议**(深夜施工、随意丢弃建筑垃圾、损坏 3 处公共设施),物业累计要扣 ¥6,000,而账户只有 ¥5,000。其间刘先生拒绝补缴,账户被冻结进入仲裁。仲裁裁决"业户全责,押金 ¥5,000 全部用于罚款,差额 ¥1,000 业户另行支付"。
>
> 物业财务依据仲裁书走 ForceClose forfeit,把账户里的 ¥5,000 全扣转入物业收入,账户关闭。差额 ¥1,000 通过司法执行另案处理(不在本系统内)。
## 业户视角
### 您会感受到什么
- 收到通知:"您的押金账户已结清,余额 ¥5,000 全额扣罚"
- 收到**红字收据**:"装修保证金扣罚 ¥-5,000(强制关账扣罚,事由:仲裁裁决业户全责)"
- 银行 / 微信**没有退款**(钱已转入物业收入)
- 小程序"我的押金账户"显示 "🔒 已结清,余额 0"
### 您要做什么
- 接受裁决结果(钱已转出账户,无法追回)
- 保管红字收据(税务凭证,有时报税)
- 如有异议走司法上诉(不在本系统内)
## 业务人员视角
### 第 1 步:确认全扣判定
- 仲裁裁决书 / 司法判决书 / 物业内部决议(必须书面)
- 物业内部已审批,具备实施权限
> [!warning] 比 ForceClose refund 更敏感
> 全扣是把业户的钱全部转入物业,**法律风险**比"全退"更高。书面凭证必须完整,内部多层审批,任何疏漏未来纠纷物业败诉概率大。
### 第 2 步:打开 Frozen 账户
后台 → 保证金 → 账户列表 → 找 Frozen 账户 → 进 `ViewDepositAccount`
### 第 3 步:点击 `ForceCloseAction`(标签"强制关账")
Modal 表单:
| 字段 | 填什么 |
|---|---|
| **处置方式 (disposition)** | 选 ✅ **`forfeit`(扣罚)** |
| **扣罚事由(memo)** | 必填且详细。例: "2026-XX-XX 仲裁案号 XXX 裁决:业户多次违约,押金 5000 全额作为罚款。" |
> [!info] forfeit 不需要选退款渠道
> 扣罚的钱**不退给业户**,直接转入物业收入,无需 PaymentChannel。Modal 表单选 forfeit 后退款渠道字段隐藏。
> [!warning] Policy 守护
> 同 [[force-close-refund]]:`update` 权限 + `isFrozen() && hasBalance()`。
### 第 4 步:提交
系统调 `ForceCloseDepositAccountAction(disposition=forfeit)`,事务内:
1. 校验 `isFrozen() && hasBalance()`
2.`CollectionOrder`(`actual_amount=-5000` 红字,`status=Completed`)—— 表达"从代管负债转出"
3.`DepositTransaction`(`type=forfeiture`,`amount=5000`,`balance_before=5000`,`balance_after=0`,关联红字 CO)
4. 更新 `balance=0`
5. 直接 `status=Closed`(Frozen → Closed)
6.`meta.force_closed_disposition=forfeit``meta.force_closed_memo=...``meta.force_closed_at=...` 记审计字段
7. 触发 `CollectionOrderCompleted` → Listener 建红字 Receipt"装修保证金扣罚 ¥-5,000(强制关账扣罚,事由 XXX)"
### 第 5 步:无线下退款,只给红字凭证
后台找到红字 Receipt → 发业户。**不要走任何转账操作** —— 资金已通过 forfeiture 流水转入物业维修收入科目,账面已完成。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 财务
participant Filament
participant ForceCloseDepositAccountAction
participant 数据库
participant 监听器
Note over 业户,财务: 账户 Frozen + balance=5000,仲裁裁决全扣
财务->>Filament: ViewDepositAccount → ForceCloseAction (disposition=forfeit)
Filament->>ForceCloseDepositAccountAction: handle(account, disposition=forfeit, memo)
ForceCloseDepositAccountAction->>ForceCloseDepositAccountAction: isFrozen() && hasBalance()? yes
ForceCloseDepositAccountAction->>数据库: 开启事务
ForceCloseDepositAccountAction->>数据库: 1. 建 CO (-5000 红字, Completed)
ForceCloseDepositAccountAction->>数据库: 2. 建 DepositTransaction (forfeiture, 5000→0)
ForceCloseDepositAccountAction->>数据库: 3. balance=0, status=Closed
ForceCloseDepositAccountAction->>数据库: 4. meta.force_closed_disposition=forfeit + memo + at
ForceCloseDepositAccountAction->>监听器: 5. 触发 CollectionOrderCompleted
监听器->>数据库: 6. 建 Receipt (强制关账扣罚 ¥-5,000)
ForceCloseDepositAccountAction->>数据库: 提交事务
Filament-->>财务: 成功通知
财务-->>业户: 红字凭证(无退款)
```
## 资金流意义
```mermaid
flowchart LR
A[业户押金 5000<br/>物业代管负债] -->|forfeit| B[物业维修/罚没收入<br/>5000]
```
会计上:**其他应付款 → 装修维修收入**,资金从未离开物业账户,只是科目变化。
## 常见问题
> [!question] forfeit 的钱进什么科目?
> 通常进"装修维修收入"或"罚没收入"科目(视物业财务核算细则)。账面通过 `Receipt` 上的 line item 描述触发科目映射(Listener `generateDepositReceiptItems` 按 `DepositTransaction.type=forfeiture` 选词)。
> [!question] 业户能反悔追讨吗?
> 已扣的钱要回去**只能走司法**:
> - 业户起诉物业不当扣罚
> - 法院判决物业败诉 → 物业按判决退款(可能需开新账户做反向 deposit + refund 操作记账,审计完整)
> - 法院判决物业胜诉 → 维持原状
>
> 系统层面的 ForceClose 不可逆,司法判决物业败诉走"补偿"路径,不"撤销"原 ForceClose。
> [!question] 仲裁裁决有补充条款(例如要求物业方做某些工作)怎么办?
> 系统只处理资金,补充条款(如修复方案、整改要求)需物业线下执行 + 留档。系统不强制关联。
> [!question] 业户已经搬走,联系不上怎么给红字收据?
> 系统层面凭证已生成,业务上若联系不上业户:
> - 用挂号信寄到登记地址
> - 物业内部档案保留
> - 等业户联系时再补发
>
> 如果业户失联前提下连扣罚都不应做(可能未让业户充分应诉),走 [[force-close-retain|资金保留]] 等业户出现更稳妥。
> [!question] 比 forfeit 多扣怎么办(扣 5000 还不够,要扣 6000)?
> 账户最多扣到余额清零(`amount ≤ balance` 守护)。**差额追偿不在本系统内**:
> - 单独的 [[adhoc-flow-a-vs-flow-b|adhoc 一次性收费]] 流(开违约金账单)
> - 司法执行(系统不参与)
## 异常分支
- 部分扣部分退 → 走 [[unfreeze-after-mediation|解冻]] + 普通 [[refund-partial-after-forfeit|扣罚后退余]]
- 全退给业户 → [[force-close-refund]]
- 资金保留待定 → [[force-close-retain]]
## 相关文档
- [[force-close-refund]]
- [[force-close-retain]]
- [[freeze-during-dispute]]
- [[account-state-machine]]
- [[forfeit-damage-public-area]]

View File

@@ -0,0 +1,230 @@
---
title: prop-acc · deposit · 场景 - 资金保留并关账(法律保留/业户失联)
aliases:
- 强制保留关账
- ForceClose retain
- 资金保留归档
- force-close-retain
- 场景-押金资金保留关账
tags:
- 场景
- prop-acc
- 保证金
- 强制关账
audience:
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:资金保留并关账(法律保留 / 业户失联)
账户 **Frozen** 状态、**有余额**,但**不确定该退还还是扣罚** —— 业户失联、遗产分配延迟、法律保留期未满、案件审理中等。物业用 `ForceCloseAction``retain` disposition,**关闭账户但保留余额** —— 资金留在物业账上,等业户回来或法律决定。
## 典型情境
> [!example] 真实情境(一)
> 装修公司倒闭,法人失联。"王装修有限公司"账户里还有 ¥15,000(为 3 户业主代缴的押金)。3 户业主中 2 户已自费维修,1 户仍在装修。物业不知该退给装修公司(已失联)、退给业主(账面缴款人不是业主)、还是扣罚作维修款。决定:**保留资金,关账户,等法律或公司清算结果**。
> [!example] 真实情境(二)
> 张阿姨因家中变故住进养老院,装修保证金账户里还有 ¥4,000。家属正在办继承公证,需 6 个月。物业不能擅自退给"自称是子女的人",也不能扣罚(无任何违约)。**保留资金,关账户,等继承公证结果**。
## 业户 / 业户家属视角
### 您(或亲属)会感受到什么
- 账户被关闭,但**没有任何退款**或扣罚通知
- 系统通知:"您的押金账户已结清,资金 ¥X 暂留物业代管,事由 XXX"
- 小程序"我的押金账户"显示 "🔒 已结清,余额保留中"
- **资金仍属于您 / 您家属 / 法定继承人**,物业不可挪用
### 您要做什么
- 在法律 / 继承 / 公司清算等程序结束后,**主动联系物业**
- 出示身份证明(本人 / 继承证明 / 司法授权文件)
- 物业核实后**重新进入退款流程**(走线下操作,系统层面**不重启账户**)
## 业务人员视角
### 第 1 步:确认 retain 判定
**业务上要符合**以下任一情境:
- 业户失联(无法核实身份,无法退款)
- 业户已故,继承未定
- 装修公司清算 / 倒闭,无明确债权人
- 法律保留期内(司法要求资金不动)
- 任何**不该退、不该扣**的临时归档需求
> [!warning] 不要把 retain 当万能选项
> retain 是为**长期不确定**的情境设计的。短期纠纷应走 [[freeze-during-dispute|冻结]] 等结果。retain 是终态,关账后**永久无法在本账户继续操作**。
### 第 2 步:打开 Frozen 账户
后台 → 保证金 → 账户列表 → 找 Frozen 账户 → 进 `ViewDepositAccount`
### 第 3 步:点击 `ForceCloseAction`(标签"强制关账")
Modal 表单:
| 字段 | 填什么 |
|---|---|
| **处置方式 (disposition)** | 选 ✅ **`retain`(保留归档)** |
| **保留事由(retain_reason)** | **必填**(关键!),如 "装修公司倒闭,3 户业主代缴款,清算未结" |
| **关账事由(memo)** | 必填,如 "ForceClose retain,等待清算结果" |
> [!info] retain_reason 与 memo 的区别
> - `retain_reason`:**业务背景**,为什么保留(写给将来要追溯的人看)
> - `memo`:**操作意图**,这次操作做了什么
>
> 两个字段都进 `meta`,审计时一起查。
> [!warning] retain 不写 retain_reason 会被守护拦截
> `ForceCloseDepositAccountAction` 对 disposition=retain 时强制要求 `retain_reason` 非空。这是刻意设计 —— 防止"无理由保留"导致后续追溯困难。
### 第 4 步:提交
系统调 `ForceCloseDepositAccountAction(disposition=retain)`,事务内:
1. 校验 `isFrozen() && hasBalance()`
2. 校验 `retain_reason` 非空
3. **不建 CollectionOrder**(没有资金动作,余额不变)
4. **不建 DepositTransaction**(同上)
5. **不建 Receipt**(同上)
6. 更新 `status=Closed`(从 Frozen)
7.`meta` 写入审计字段:
- `force_closed_disposition: 'retain'`
- `force_closed_memo: ...`
- `force_closed_at: now`
- **`balance_held_amount`**: 保留的金额
- **`balance_held_reason`**: retain_reason 的副本
8. 账户 `balance` 字段保持原值(例如 ¥5,000)—— **不清零**
### 第 5 步:线下记录归档
- 物业财务把这种"已 Closed 但有余额"账户列入**待处理代管资金清单**
- 银行账户里对应的资金做**专项隔离**(账面与物业自有资金分开)
- 每月 / 每季对账时核对
### 第 6 步:业户出现时
业户(或家属 / 继承人 / 清算人)出现并出示合法身份后:
| 选项 | 操作 |
|---|---|
| 退还给业户 | **开新账户** → 走 `Deposit` 把 retain 余额转入新账户(系统层 deposit + 备注"原 retain 账户转入")→ 立刻 [[refund-full-no-damage|退款]] |
| 扣罚处理 | **开新账户** → 同上流程 → [[forfeit-damage-public-area|扣罚]] |
| 物业内部决议无主资金 | 走法律程序(物业法务 / 街道办)→ 司法判决归属 → 按判决处理 |
> [!warning] 不要试图"重启" Closed 账户
> Closed 账户永久关闭。`canBeReopened` 永远 false。所有"业户回来了"的处理都通过**新账户**走。
## 系统流程
```mermaid
sequenceDiagram
participant 业户家属
participant 财务
participant Filament
participant ForceCloseDepositAccountAction
participant 数据库
Note over 业户家属,财务: 业户失联,余额 5000 留 Frozen 状态
财务->>Filament: ViewDepositAccount → ForceCloseAction(disposition=retain, retain_reason)
Filament->>ForceCloseDepositAccountAction: handle(account, retain, retain_reason, memo)
ForceCloseDepositAccountAction->>ForceCloseDepositAccountAction: isFrozen() && hasBalance()? yes
ForceCloseDepositAccountAction->>ForceCloseDepositAccountAction: retain_reason 非空? yes
ForceCloseDepositAccountAction->>数据库: 开启事务
ForceCloseDepositAccountAction->>数据库: 1. balance 不变(5000)
ForceCloseDepositAccountAction->>数据库: 2. status=Closed
ForceCloseDepositAccountAction->>数据库: 3. meta.force_closed_disposition=retain<br/>+ balance_held_amount=5000<br/>+ balance_held_reason
Note over 数据库: 不建 CO/Transaction/Receipt
ForceCloseDepositAccountAction->>数据库: 提交事务
Filament-->>财务: 成功通知
Note over 业户家属,财务: 数年后家属持继承公证出现
业户家属->>财务: 我是继承人,要领回 5000
财务->>财务: 核验继承文件
财务->>Filament: 开新 DepositAccount + 缴款 5000 (备注"原 retain 转入")
财务->>Filament: 立即 RefundAction (5000) → 自动 Closed
财务-->>业户家属: 退款 + 红字收据
```
## 流水台账(本场景完整记录)
| 流水 | 说明 |
|---|---|
| (无)| 整个 retain 关账过程**没有任何 DepositTransaction**,余额未变,只有账户状态变更 + meta 审计字段 |
后续如果业户家属出现:
| 流水 | 说明 |
|---|---|
| (新账户的)deposit | 把 retain 余额转入新账户 |
| (新账户的)refund | 退给业户家属 |
## meta 字段示例(retain 关账后)
```json
{
"force_closed_disposition": "retain",
"force_closed_memo": "ForceClose retain,等待清算结果",
"force_closed_at": "2026-05-25T14:32:01+08:00",
"force_closed_by": 42,
"balance_held_amount": 5000.00,
"balance_held_reason": "装修公司倒闭,3 户业主代缴款,清算未结"
}
```
## 常见问题
> [!question] retain 后账户有余额但 status=Closed,这不是矛盾吗?
> 不矛盾。Closed 表示"业务终结",`balance` 字段表示"账面余额"。两者**独立**:
>
> - Closed + balance=0:正常关账(refund / forfeit 后)
> - Closed + balance>0:retain 关账,业务终结但资金仍归业户
>
> 系统设计上,`canBeClosed()` 要求 `balance==0` 是给**正常路径**用的;ForceClose 走专用 Policy 不受此限制。
> [!question] retain 之后报表上余额怎么算?
> 物业代管资金报表:
> - 全 Active 账户 `balance` 之和
> - **加上** Closed 账户中 `meta.balance_held_amount` 之和
>
> 后者是"待处置代管资金",银行账户里对应的钱仍属业户。详见 [[audit-monthly-deposit-balance]]。
> [!question] retain 的资金物业能挪用吗?
> **不能,法律上是业户的钱**。物业的会计科目仍为"其他应付款",银行账户里这部分资金做隔离专户最规范。任何挪用都是违法。
> [!question] 长期 retain(10 年以上)的资金怎么处理?
> 根据各地民法 / 物业管理条例,长期无主资金可能转入:
> - 街道办无主资金账户
> - 公益基金
> - 财政
>
> 具体走流程视司法管辖,**系统不主动处理** —— 物业法务发起,系统配合记录(可能在该账户 meta 加一笔 `transferred_to_*` 备注,或者依照流程做反向 forfeit 然后转出)。
> [!question] retain 的金额能在已关账户上"动一下"吗(例如部分释放、部分继续保留)?
> 不能。账户 Closed 后任何操作都不允许。如果业务需要"部分释放":开新账户 → 把保留余额按 X 元转入(deposit)→ 退给业户(refund)→ 剩余在新账户继续 retain(再 ForceClose retain 一次)。
> [!question] retain 不写 retain_reason 系统会怎样?
> `ForceCloseDepositAccountAction` 会校验失败,抛出错误。Modal 表单也会前端校验阻止提交。这是**刻意设计**:无理由 retain = 后续无法追溯 = 不合规。
## 异常分支
- 业户出现配合退款 → 开新账户 + deposit + refund(详见上方"业户出现时"步骤)
- 业户最终被司法判定无主 → 物业法务发起转出流程
- 短期纠纷不适用 retain → 走 [[freeze-during-dispute]] 然后 [[unfreeze-after-mediation]]
## 相关文档
- [[force-close-refund]]
- [[force-close-forfeit]]
- [[account-state-machine]]
- [[freeze-during-dispute]]
- [[audit-monthly-deposit-balance]]
- [[audit-long-pending-accounts]]