diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json
index e9981a0..78bb931 100644
--- a/.obsidian/workspace.json
+++ b/.obsidian/workspace.json
@@ -196,6 +196,10 @@
},
"active": "b06ed69835363258",
"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/close-manual-with-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/deposit-account-vs-transaction.md",
"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/concepts/adhoc",
"resident-portal/scenarios",
diff --git a/prop-acc/scenarios/deposit/audit-monthly-deposit-balance.md b/prop-acc/scenarios/deposit/audit-monthly-deposit-balance.md
new file mode 100644
index 0000000..916f744
--- /dev/null
+++ b/prop-acc/scenarios/deposit/audit-monthly-deposit-balance.md
@@ -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]]
diff --git a/prop-acc/scenarios/deposit/exception-deposit-on-frozen.md b/prop-acc/scenarios/deposit/exception-deposit-on-frozen.md
new file mode 100644
index 0000000..7ddc22f
--- /dev/null
+++ b/prop-acc/scenarios/deposit/exception-deposit-on-frozen.md
@@ -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]]
diff --git a/prop-acc/scenarios/deposit/force-close-forfeit.md b/prop-acc/scenarios/deposit/force-close-forfeit.md
new file mode 100644
index 0000000..f97b0ad
--- /dev/null
+++ b/prop-acc/scenarios/deposit/force-close-forfeit.md
@@ -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
物业代管负债] -->|forfeit| B[物业维修/罚没收入
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]]
diff --git a/prop-acc/scenarios/deposit/force-close-retain.md b/prop-acc/scenarios/deposit/force-close-retain.md
new file mode 100644
index 0000000..8c2e77b
--- /dev/null
+++ b/prop-acc/scenarios/deposit/force-close-retain.md
@@ -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
+ balance_held_amount=5000
+ 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]]