vault backup: 2026-05-25 22:22:37

This commit is contained in:
Willie
2026-05-25 22:22:37 +08:00
parent d169be22a5
commit 5482164460
5 changed files with 673 additions and 16 deletions

View File

@@ -0,0 +1,147 @@
---
title: prop-acc · deposit · 场景 - 已有账户追加缴款
aliases:
- 追加缴款
- 押金账户追加
- deposit-additional-topup
- 场景-押金追加缴款
tags:
- 场景
- prop-acc
- 保证金
- 缴纳
audience:
- 业户
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:已有账户后续追加缴款
业户**已经有一个 Active 状态的押金账户**,现在要追加缴款(扩大装修范围 / 押金标准提升 / 分期补齐)。比首次开户简单 —— 不重建账户,只加流水。
## 典型情境
> [!example] 真实情境
> 张阿姨家原来交了 ¥3,000 装修保证金。装修过程中她决定多动一面承重墙,物业要求她**补 ¥2,000 押金**(高风险装修加押)。第二天她到前台补缴。
## 业户视角
### 第 1 步:到前台 / 小程序
带身份证(部分物业要求)到前台,告诉职员:
> "我要给装修押金账户补 ¥2,000。"
### 第 2 步:付款
同 [[deposit-first-time-renovation|首次缴款]]:现金 / 微信 / POS / 银行转账。
### 第 3 步:拿收据
新收据"装修保证金缴纳 ¥2,000"。
> [!info] 您账户里现在有多少?
> 旧 ¥3,000 + 新 ¥2,000 = **¥5,000**。下次退押时按这个总数算。
## 业务人员视角
> [!info] 与首次缴款的关键差异
> **不开新账户,在既有账户上加缴款流水**。如果误开新账户,会出现两个并行账户,退款时一笔退不清,业户会困惑。
### 第 1 步:找到既有账户
后台 → 保证金 → 账户列表 → 按业户姓名 / 房号 / 缴款人姓名搜索 → 找到 Active 账户。
### 第 2 步:进入账户详情(`ViewDepositAccount`)
详情页右上角的状态管理组里点 **`DepositAction`** 按钮(标签"追加缴款")。
> [!warning] 按钮可能灰化
> 仅当账户 `status=Active` 时可点。Frozen / Closed 状态下灰化。详见 [[account-state-machine]] 的 `canDeposit()` 守护。
### 第 3 步:Modal 表单
| 字段 | 填什么 |
|---|---|
| 缴款金额 | ¥2,000 |
| 支付方式 | 现金 / 微信 / POS / 银行转账 |
| 收款银行账户 | 微信/POS/转账选对应银行 |
| 备注 | 选填,如 "动承重墙加押" |
### 第 4 步:提交
系统调用业务层 `DepositIntoAccountAction`,在事务内:
1. 校验账户 `canDeposit()`(Active only)
2.`CollectionOrder`(`actual_amount=+2000`,`status=Completed`)
3. 在既有账户上加 `DepositTransaction`(`type=deposit`,`amount=2000`,`balance_before=3000`,`balance_after=5000`,关联 CO)
4. 更新 `DepositAccount.balance` = 5000
5. 触发 `CollectionOrderCompleted` → Listener 自动建 Receipt
### 第 5 步:给收据
后台找到新生成的 Receipt(只对应这一笔追加),交给业户。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 前台
participant Filament
participant DepositIntoAccountAction
participant 数据库
participant 监听器
业户->>前台: 给押金账户加 2000
前台->>Filament: ViewDepositAccount → DepositAction(modal)
Filament->>DepositIntoAccountAction: handle(account, 2000, paymentChannel)
DepositIntoAccountAction->>DepositIntoAccountAction: canDeposit() ? (Active=true)
DepositIntoAccountAction->>数据库: 开启事务
DepositIntoAccountAction->>数据库: 1. 建 CollectionOrder (+2000, Completed)
DepositIntoAccountAction->>数据库: 2. 建 DepositTransaction (deposit, 3000→5000)
DepositIntoAccountAction->>数据库: 3. 更新 DepositAccount.balance=5000
DepositIntoAccountAction->>监听器: 4. 触发 CollectionOrderCompleted
监听器->>数据库: 5. 建 Receipt (装修保证金缴纳 ¥2,000)
DepositIntoAccountAction->>数据库: 提交事务
Filament-->>前台: 成功通知 + 刷新余额显示
前台->>业户: 给新收据
```
> [!info] 一处代码,两处入口
> `DepositIntoAccountAction` 是**两处调用方共用**的业务 Action:
> - 本场景(追加缴款):从 `ViewDepositAccount` → `DepositAction` 触发
> - [[deposit-first-time-renovation|首次开户]]:从 `CreateDepositAccount` 表单触发
>
> 未来若小程序在线缴款,也复用同一份。逻辑只写一遍。
## 常见问题
> [!question] Frozen 账户能追加缴款吗?
> **不能**。`canDeposit()` 只允许 `Active`。Frozen 状态下按钮灰化,直接调 Action 会抛 `RuntimeException`。
>
> 这条规则比直觉更严:看上去"多存钱不亏",但实际风险是纠纷期间装修公司继续往受冻结账户灌钱,资金被困、责任更复杂。详见 [[account-state-machine]] "关键守护" 段。
> [!question] Closed 账户呢?
> 同样**不能**。Closed 是永久终态,新业务请[[deposit-first-time-renovation|开新账户]]。
> [!question] 多次追加缴款,余额怎么算?
> 每笔 `DepositTransaction` 都有 `balance_before` 和 `balance_after`,账户 `balance` 字段也实时更新。任何时刻业户问"我现在有多少押金",看 `DepositAccount.balance` 即可。审计可重算 `SUM(deposit) - SUM(refund) - SUM(forfeiture)` 校验自洽。
> [!question] 追加缴款的收据是单独一张还是合并到原收据?
> **单独一张**。每笔 `DepositTransaction` 对应一张独立的 `Receipt`。这与"原单上挂退款标记"的反模式相反,详见 [[red-receipt-design]] "为什么不在原 CollectionOrder 上挂退款标记" 段。
> [!question] 业户能在小程序自助追加缴款吗?
> 待补。当前 Action 假设手工操作(前台触发)。未来加小程序在线支付时,前端调同一个 `DepositIntoAccountAction`,只需多加一个支付回调入口。
## 相关文档
- [[deposit-first-time-renovation]]
- [[account-state-machine]]
- [[deposit-account-vs-transaction]]
- [[transaction-types]]
- [[exception-deposit-on-frozen]]

View File

@@ -0,0 +1,165 @@
---
title: prop-acc · deposit · 场景 - 装修业户首次缴 5000 保证金
aliases:
- 首次缴装修保证金
- deposit-first-time-renovation
- 场景-装修业户首次缴保证金
tags:
- 场景
- prop-acc
- 保证金
- 缴纳
audience:
- 业户
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:装修业户首次缴 5,000 保证金
最常见的保证金场景。业户准备装修,**第一次**给物业交装修押金,系统**当场建账户 + 收钱 + 出收据**。
## 典型情境
> [!example] 真实情境
> 张阿姨,72 岁,儿子要装修她家(12-3-501)。装修前一天她带着身份证、房产证、装修施工合同来物业前台,要交 ¥5,000 装修保证金。
## 业户视角(您要做什么)
### 第 1 步:到前台带齐材料
- 身份证(或户口本)
- 房产证(或租赁合同 + 业主授权书)
- 装修施工合同(物业要存档,确认装修方信息)
### 第 2 步:告诉职员
"我家要装修了,来交装修保证金,房号 12-3-501。"
### 第 3 步:付款
职员告诉您**多少钱**(常见 ¥3,000-10,000,各小区不同),您可选:
- **现金**
- **微信扫码**
- **POS 刷卡**
- **银行转账**(需打印银行凭证)
### 第 4 步:拿收据
- 纸质收据:**当场打印**
- 电子收据:发到您的微信或邮箱
> [!success] 完成
> 整个过程 10 分钟内搞定。收据写"装修保证金缴纳 ¥5,000",妥善保管,装修结束时退押凭这个。
## 业务人员视角(物业职员怎么操作)
> [!info] 关键差异
> 这是**首次**开户 + 缴款。之后追加缴款走 [[deposit-additional-topup]],流程更简短。
### 第 1 步:打开后台
登录 Filament 后台 → 保证金 → **新建账户**(`CreateDepositAccount` 页面)。
### 第 2 步:填表单(账户信息)
| 字段 | 填什么 |
|---|---|
| **缴款人类型(`payer_type`)** | 选 `Owner`(业主)/ `Tenant`(租户)/ `Contractor`(承包商)等;详见 [[payer-types]] |
| **缴款人姓名(`payer_name`)** | "张某某" |
| **缴款人联系方式(`payer_contact`)** | 张阿姨手机号 |
| **业户档案(`community_user_profile_id`)** | 通过房号 12-3-501 找到张阿姨绑定的业户档案(Owner / Tenant 类型必填) |
| **房屋单元(`asset_id`)** | 12-3-501 房屋资产 |
| **押金种类(`fee_type_id`)** | "装修保证金"(本物业项目预先配置的 FeeType) |
| **备注(`remark`)** | 选填,如 "2026 年春季装修,施工方:王装修有限公司" |
### 第 3 步:填首次缴款信息
`CreateDepositAccount` 页面下半部分有"首次缴款"段,**和开户一起一气呵成**:
| 字段 | 填什么 |
|---|---|
| **缴款金额** | ¥5,000 |
| **支付方式(PaymentChannel)** | 现金 / 微信 / POS / 银行转账 |
| **收款银行账户** | 微信/POS/转账选对应银行;现金可空 |
| **缴款备注** | 选填,如 "首次开户缴款" |
### 第 4 步:提交
点击"创建"。系统在一个数据库事务内完成:
1.`DepositAccount`(`status=Active`,`balance=5000`)
2.`CollectionOrder`(`actual_amount=+5000`,`status=Completed`)
3.`DepositTransaction`(`type=deposit`,`amount=5000`,`balance_before=0`,`balance_after=5000`,关联 CO)
4. 触发 `CollectionOrderCompleted` 事件
5. Listener 自动建 `Receipt` + `ReceiptItem`,文案"装修保证金缴纳 ¥5,000"
### 第 5 步:打印 / 发收据
- 后台收据列表找到刚生成的 Receipt → 点击"打印"或"发送"
- 把纸质收据交给张阿姨,或直接微信发她
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 前台
participant Filament
participant 数据库
participant 监听器
业户->>前台: 我要交装修保证金 5000(现金)
前台->>Filament: CreateDepositAccount 填表 + 提交
Filament->>数据库: 开启事务
Filament->>数据库: 1. 建 DepositAccount (Active, balance=5000)
Filament->>数据库: 2. 建 CollectionOrder (actual=+5000, Completed)
Filament->>数据库: 3. 建 DepositTransaction (deposit, balance 0→5000)
Filament->>监听器: 4. 触发 CollectionOrderCompleted
监听器->>数据库: 5. 建 Receipt + ReceiptItem ("装修保证金缴纳 ¥5,000")
Filament->>数据库: 提交事务
Filament-->>前台: 成功通知 + 显示新账户
前台->>业户: 给收据
```
> [!info] 一气呵成
> 5 个数据库写入在同一事务里。任何一步失败,整笔回滚 —— 不会出现"账户建了但钱没记""收据生成了但流水没建"的半成品状态。
## 常见问题
> [!question] 业户没带身份证 / 房产证可以办吗?
> 各物业政策不同,系统不强制证件检查。属于物业内部审核流程。
> [!question] 装修方是装修公司不是业户,该怎么开?
> 走 [[deposit-on-behalf-by-company]] 流程:`payer_type=Company`,不绑业户档案,只记公司名 + 联系人。
> [!question] 业户没带够现金可以拆分付款吗?
> 单笔 `CollectionOrder` 只支持一种支付方式。可以**先开账户缴一部分**,过几天 [[deposit-additional-topup|追加缴款]] 补齐。
> [!question] 录错金额(把 ¥5,000 录成 ¥50,000)怎么办?
> 不要试图改流水,流水是不可变的。正确做法:建一笔 `Refund` 退还多收的差额,业户拿到一张红字收据。详见 [[transaction-types]] "真实修正场景示例" 段。
> [!question] 这个账户绑了张阿姨,但实际付钱的是她儿子,可以吗?
> 系统只看 `payer_*` 字段。如果想严格反映"儿子代付",可在 `payer_name` 写儿子名 + `community_user_profile_id` 仍绑张阿姨;退款时收据上文案会按 `payer_name` 显示。或者继续用张阿姨名,备注里说明。
> [!question] 同一业户能开多个押金账户吗?
> 可以,只要 `(community_id, fee_type_id, payer_type, asset_id)` 组合不同。例如张阿姨可以同时有"装修保证金"和"入驻押金"两个账户,各自独立。
## 异常分支
- 录错金额想撤回 → [[refund-partial-after-forfeit]] 或 [[refund-full-no-damage]]
- 装修过程出问题(损坏 / 违约)→ [[forfeit-damage-public-area]] / [[forfeit-violation-no-permit]]
- 业户和物业有纠纷暂时冻结 → [[freeze-during-dispute]]
- 已开账户后续追加 → [[deposit-additional-topup]]
## 相关文档
- [[deposit-account-vs-transaction]]
- [[account-state-machine]]
- [[payer-types]]
- [[refund-full-no-damage]]
- [[deposit-additional-topup]]

View File

@@ -0,0 +1,163 @@
---
title: prop-acc · deposit · 场景 - 装修公司代业户缴纳
aliases:
- 装修公司代缴
- 三方账户开户
- deposit-on-behalf-by-company
- 场景-装修公司代缴
tags:
- 场景
- prop-acc
- 保证金
- 缴纳
- 三方账户
audience:
- 业户
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:装修公司代业户缴纳
装修公司本月承接小区**多户业主**装修,公司账户**一次性垫付**多张保证金。每户单独开账户,缴款人记公司而非业主。
## 典型情境
> [!example] 真实情境
> 王老板的"王装修有限公司"本月在小区承接 **3 户业主**(12-3-501 / 12-3-502 / 12-3-503)的装修。三户业主都让王老板帮忙付保证金,王老板直接刷公司对公账户一笔转 ¥15,000 到物业。物业要为这 3 户分别开 3 个押金账户。
## 业户视角(装修公司王老板)
### 第 1 步:到前台带齐材料
- 营业执照(公司主体证明)
- 三户业主的装修施工合同(每户一份)
- 三户业主的授权书(允许王装修代缴押金)
- 三户房产证复印件
- 公司对公账户银行卡(用于退款时回款)
### 第 2 步:告诉职员
> "我帮 501、502、503 三户业主交装修保证金,每户 ¥5,000,从我公司账户一笔转 ¥15,000 过来。"
### 第 3 步:对公转账
把 ¥15,000 转到物业指定收款账户(转账备注写"3 户装修押金代缴")。
### 第 4 步:拿 3 张收据
物业为每户单独建账户、单独出收据。您拿到:
- 收据 1:"装修保证金缴纳 ¥5,000(12-3-501,业主李某某)"
- 收据 2:"装修保证金缴纳 ¥5,000(12-3-502,业主陈某某)"
- 收据 3:"装修保证金缴纳 ¥5,000(12-3-503,业主刘某某)"
每张收据"缴款人"写**王装修有限公司**(您),但"关联业户"写对应业主。
> [!warning] 退款回哪
> 退款时**退到您公司对公账户**(因为缴款人是您),不是退给业主。三户结清后您拿到 3 张红字退款收据,自己再跟业主结清。
## 业务人员视角(物业职员)
> [!info] 关键差异
> 与 [[deposit-first-time-renovation|业主自缴]]的最大不同:
> - `payer_type = Company`(不是 Owner)
> - **不绑业户档案**(`community_user_profile_id = NULL`)
> - 用 `payer_name` + `payer_contact` 记公司名 + 联系人
> - 但**仍绑业户档案到 `community_user_profile_id` 是允许的** —— 若你想精确表达"代缴的对象是哪位业主",可以填业主的 profile id,系统不强制三方账户为空
### 第 1 步:为每户开账户(3 个)
每户单独打开 `CreateDepositAccount`,填:
| 字段 | 12-3-501 | 12-3-502 | 12-3-503 |
|---|---|---|---|
| `payer_type` | `Company` | `Company` | `Company` |
| `payer_name` | "王装修有限公司" | "王装修有限公司" | "王装修有限公司" |
| `payer_contact` | 王老板手机 | 王老板手机 | 王老板手机 |
| `community_user_profile_id` | 业主李某某(可选,推荐填) | 业主陈某某(可选) | 业主刘某某(可选) |
| `asset_id` | 12-3-501 房屋 | 12-3-502 房屋 | 12-3-503 房屋 |
| `fee_type_id` | 装修保证金 | 装修保证金 | 装修保证金 |
| 首次缴款金额 | ¥5,000 | ¥5,000 | ¥5,000 |
| 支付方式 | 银行转账 | 银行转账 | 银行转账 |
| 收款银行账户 | 物业指定收款账户 | 同上 | 同上 |
| 备注 | "王装修代缴" | "王装修代缴" | "王装修代缴" |
提交 3 次,生成 3 个独立的 `DepositAccount` + 3 张 Receipt。
### 第 2 步:核对对公转账记录
物业会计核对银行流水:王装修一笔转入 ¥15,000 == 3 张 Receipt 合计 ¥15,000 ✅。
### 第 3 步:把 3 张收据交给王老板
> [!tip] 不要把收据交给业主
> 业主交的不是这笔钱,收据上"缴款人"是公司。给业主反而会让退款时找钱方向混乱。
## 系统视角:为什么不能一个账户装多户
> [!warning] 反模式
> 看起来"王装修一个账户记 ¥15,000 余额"很简洁,但**会出大问题**:
>
> 1. **退款时谁的钱是谁的算不清** —— 501 装修完先退,要从 ¥15,000 里退 ¥5,000,剩 ¥10,000 是哪两户的?
> 2. **每户的扣罚责任无法独立** —— 502 砸了公共墙,要从 502 的 ¥5,000 里扣,但账户里钱已经混了
> 3. **业主侧无法查询自己的押金状态** —— 业主在小程序看"我的押金",看不到自己 ¥5,000,只看到一个公司账户
>
> 所以即使是"一笔转账",**也必须开 N 个独立账户**,每个对应一户。系统设计的"账户 + 流水"模式天然支持这种细颗粒度,详见 [[deposit-account-vs-transaction]]。
## 系统流程
```mermaid
sequenceDiagram
participant 王装修
participant 前台
participant Filament
participant 数据库
participant 监听器
王装修->>前台: 我帮 3 户业主交押金,公司对公转 15000
Note over 前台: 核对转账已到账
loop 3 次(每户一次)
前台->>Filament: CreateDepositAccount (payer=Company, asset=N号房, amount=5000)
Filament->>数据库: 建 DepositAccount + CO (+5000) + DepositTransaction
Filament->>监听器: 触发 CollectionOrderCompleted
监听器->>数据库: 建 Receipt ("装修保证金缴纳 ¥5,000")
end
前台->>王装修: 给 3 张收据
```
## 常见问题
> [!question] 装修公司账户和业主账户在退款时差异?
> 业务上差异最大的是"退给谁":
> - Owner / Tenant 账户:退给业主本人(通常原路退,看缴款渠道)
> - Company / Contractor 账户:退给公司 / 承包商(需手工指定回款渠道)
>
> 详见 [[refund-with-payment-channel-switch]]。
> [!question] 装修公司倒闭了,押金怎么办?
> 走 [[force-close-retain]] 强制关账并保留资金,等待法律程序确定归属。
> [!question] 装修公司转包给装修队,业主想押金挂装修队怎么办?
> 重新开账户,`payer_type=Contractor`,`payer_name=` 装修队负责人。原公司账户走 [[refund-full-no-damage]] 退款给装修公司,装修队再缴一笔新账户。**不要试图改账户的 payer 字段** —— 缴款人变更等于换主体,审计无法追溯。
> [!question] 三户分账户开比一户一户开慢,有批量功能吗?
> 当前没有批量。3 户开 3 次就行,每次 ~3 分钟。如果业务上常发(装修公司频繁代缴 10+ 户)再加批量入口。
## 异常分支
- 装修公司不还业主对应押金 → 业务层面问题,系统不解决(账面退款已退给公司,后续是公司与业主民事关系)
- 业主提出"装修公司不给退我的押金,物业能直接退给我吗" → 不能。账面缴款人是公司,退款只能退公司。如有纠纷走 [[freeze-during-dispute]] 冻结 + 调解
## 相关文档
- [[deposit-first-time-renovation]]
- [[payer-types]]
- [[deposit-account-vs-transaction]]
- [[refund-with-payment-channel-switch]]
- [[force-close-retain]]

View File

@@ -0,0 +1,182 @@
---
title: prop-acc · deposit · 场景 - 装修完无损全额退还
aliases:
- 全额退还押金
- 无损装修退押
- refund-full-no-damage
- 场景-押金全额退还
tags:
- 场景
- prop-acc
- 保证金
- 退款
audience:
- 业户
- 业务人员
status: 已发布
sub_feature: deposit
last_review: 2026-05-25
code_version: 2026-05-22
---
# 场景:装修完无损全额退还
最常见、最理想的退押场景。业户装修完物业验收**无损坏无违约**,押金原额退还,账户自动关闭。
## 典型情境
> [!example] 真实情境
> 张阿姨家装修完了(花了 6 周),物业例行验收公共走道、电梯、楼栋出入口,**没有任何损坏**。张阿姨当初交了 ¥5,000 装修保证金,现在物业要全额退给她。
## 业户视角
### 第 1 步:装修完通知物业验收
- 微信通知物业管家 / 直接到前台说"我家装修完了,来验收一下退押金"
- 通常物业 2-3 个工作日内派人到现场
### 第 2 步:验收无损,等退款
- 验收员检查公共区域、电梯、楼道、出入口
- 无损 → 出验收报告"无损,准予退押"
- 物业财务凭报告办理退款
### 第 3 步:收到退款
退款方式取决于您当初**怎么交的押金**:
| 当初缴款方式 | 退款方式 |
|---|---|
| 微信扫码 | 退微信 / 银行卡 |
| 现金 | 通常退到您银行卡(物业转账)|
| 银行转账 | 原账户回款 |
| POS 刷卡 | 原卡原路退 |
> [!info] 一两个工作日内到账
> 退款不是即时,物业财务批量处理(通常隔日)。
### 第 4 步:收到红字收据
您会收到一张**红字收据**:
> "装修保证金退还 ¥-5,000"
- 金额前的负号表示"退款"
- 这是中国会计的"红字凭证"标准写法
- 妥善保管,可作税务凭证
> [!success] 完成
> 账户自动关闭,不会再有变动。短信/微信通知:"您的押金账户已结清,余额 0"。
## 业务人员视角(物业财务)
### 第 1 步:核对验收报告
确认装修完验收通过、无损坏、无未结违约。
### 第 2 步:打开账户
后台 → 保证金 → 账户列表 → 找到张阿姨的账户(Active,balance=5000)→ 点击进入 `ViewDepositAccount`
### 第 3 步:点击 `RefundAction`(标签"退款")
右上角状态管理组里。Modal 表单:
| 字段 | 填什么 |
|---|---|
| **退款金额** | ¥5,000(默认带入当前余额,可改) |
| **退款渠道(PaymentChannel)** | 选张阿姨指定的回款方式(微信 / 银行转账 / POS) |
| **退款备注** | 选填,如 "装修验收无损,全额退还" |
> [!warning] 按钮可见性
> `RefundAction` 加了 `->authorize('refund')` Policy 守护:`update` 权限 + `canWithdraw()` 状态(Active only)。Frozen / Closed 账户该按钮灰化。
### 第 4 步:提交
系统调 `RefundFromDepositAccountAction`,事务内:
1. 校验账户 `canWithdraw()`(Active only)
2. 校验金额 ≤ 当前余额
3.`CollectionOrder`(`actual_amount=-5000` 红字,`status=Completed`)
4.`DepositTransaction`(`type=refund`,`amount=5000`,`balance_before=5000`,`balance_after=0`,关联红字 CO)
5. 更新 `DepositAccount.balance=0`
6. **余额清零自动关账** → 账户 `status=Closed`
7. 触发 `CollectionOrderCompleted` → Listener 建红字 Receipt"装修保证金退还 ¥-5,000"
### 第 5 步:走线下退款流程
- 微信 / POS 退款:在对应支付网关后台操作
- 银行转账:导出回款指令交银行
- 现金退款(罕见):张阿姨到前台领现金
### 第 6 步:把红字收据交给张阿姨
后台找到红字 Receipt → 打印 / 发微信。
## 系统流程
```mermaid
sequenceDiagram
participant 业户
participant 财务
participant Filament
participant RefundFromDepositAccountAction
participant 数据库
participant 监听器
业户->>财务: 装修完了,验收无损,退押金
财务->>Filament: ViewDepositAccount → RefundAction(modal)
Filament->>RefundFromDepositAccountAction: handle(account, 5000, channel)
RefundFromDepositAccountAction->>RefundFromDepositAccountAction: canWithdraw()? (Active=true)
RefundFromDepositAccountAction->>RefundFromDepositAccountAction: amount ≤ balance? (5000≤5000)
RefundFromDepositAccountAction->>数据库: 开启事务
RefundFromDepositAccountAction->>数据库: 1. 建 CollectionOrder (-5000 红字, Completed)
RefundFromDepositAccountAction->>数据库: 2. 建 DepositTransaction (refund, 5000→0)
RefundFromDepositAccountAction->>数据库: 3. balance=0,自动 status=Closed
RefundFromDepositAccountAction->>监听器: 4. 触发 CollectionOrderCompleted
监听器->>数据库: 5. 建 Receipt (装修保证金退还 ¥-5,000 红字)
RefundFromDepositAccountAction->>数据库: 提交事务
Filament-->>财务: 成功通知
财务-->>业户: 银行/微信退款 + 红字收据
```
> [!info] 自动关账
> 余额清零时,系统自动把账户翻成 `Closed`,不需要再单独走一次 [[close-after-zero-balance|关账]] 操作。
## 常见问题
> [!question] 业户当初付现金,退款必须退现金吗?
> 不强制。退款时选 `PaymentChannel` 可以与缴款时不同。常见做法是退到业户银行卡,详见 [[refund-with-payment-channel-switch]]。
> [!question] 退一半就行可以吗?
> 可以,Modal 表单的"退款金额"字段可以改成任意 ≤ 余额的数字。剩余款还在账户里,账户保持 Active。后续可继续退或扣或关。
> [!question] 退款后红字收据上的"-"是什么意思?
> 中国会计的"红字凭证"。负数表示资金方向是"从物业流出 / 回到业户",与缴款时的"+"对称。详见 [[red-receipt-design]]。
> [!question] 业户拿到红字收据后觉得"扣了我的钱"?
> 给业户解释:
> - "-5,000" 不是"扣 5,000",是"退还 5,000"
> - 黑字(无负号)是物业收到的钱,红字(有负号)是物业退给您的钱
> - 这是会计标准做法
> [!question] 退款失败(银行退回 / 微信渠道异常)怎么办?
> 当前系统**不处理这种回调**。物业财务需要在线下沟通业户,重新指定退款渠道,然后:
> - 如果账户已关:开新账户(不推荐)或 tinker 改流水(运维介入)
> - 推荐:**业务流程上避免** —— 退款前与业户确认渠道有效
> [!question] 已关账户能反悔吗?
> 不能。`canBeReopened()` 永远 false。详见 [[account-state-machine]] "为什么不允许 Reopen" 段。如果业户反悔继续装修要再交押金,**开新账户**。
## 异常分支
- 有损坏 → 先扣 [[forfeit-damage-public-area]],再走 [[refund-partial-after-forfeit]]
- 退款渠道与缴款不同 → [[refund-with-payment-channel-switch]]
- 退款时账户 Frozen → 走 [[force-close-refund]] 强制关并退
## 相关文档
- [[deposit-account-vs-transaction]]
- [[account-state-machine]]
- [[red-receipt-design]]
- [[refund-partial-after-forfeit]]
- [[close-after-zero-balance]]