Files
uniprop-manual/prop-acc/concepts/deposit/deposit-account-vs-transaction.md
2026-05-25 22:07:35 +08:00

4.7 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 · deposit · 押金账户与押金流水
押金账户与押金流水
DepositAccount 与 DepositTransaction
押金的双对象模式
概念
prop-acc
保证金
核心概念
业户
业务人员
已发布 deposit 2026-05-25 2026-05-22

押金账户与押金流水

保证金模块底层是两个对象配合的:账户(DepositAccount)只记当前状态,流水(DepositTransaction)记每一笔变动

为什么要两个对象

[!info] 类比:银行存折

  • 账户 = 存折封面那一行"当前余额 ¥5,000"
  • 流水 = 翻开存折每一页:几号存了多少、几号取了多少、每笔的"前余额→后余额"

如果只有账户没有流水,查到余额是 ¥3,000 你不知道钱从哪里来的、被扣了什么。审计、业户对账、纠纷复盘全都失据。

如果只有流水没有账户,每次想知道当前余额都要重新累加全部历史,慢且容易脏。

所以两个都要:账户给你"现在长什么样",流水给你"如何变成现在这样"

字段速查

DepositAccount(账户)

字段 含义
id 账户 ID
community_id 所属物业项目
fee_type_id 押金种类(装修保证金 / 入驻押金 / ...)
payer_type 缴款人类型(详见 payer-types)
payer_name 缴款人姓名(冗余存,免关联 user 表)
payer_contact 缴款人联系方式
community_user_profile_id 业户档案 ID(若缴款人是平台业户)
asset_id 关联房屋单元(若与具体房屋相关)
balance 当前余额(单一事实来源)
status 账户状态(详见 account-state-machine)
opened_at 开户时间
meta JSON 扩展字段(force_closed_* 等审计标记)

DepositTransaction(流水)

字段 含义
id 流水 ID
deposit_account_id 归属账户
type 流水类型(详见 transaction-types)
amount 本笔金额(正数;退款/扣罚也是正数,方向由 type 表达)
balance_before 本笔之前账户余额
balance_after 本笔之后账户余额
related_collection_order_id 关联收款单(deposit / refund / forfeiture 都关联)
memo 备注
operated_by 操作员 ID
创建后不可变 一旦生成就只读,任何"撤销"都建新流水反向冲

两者的契约

账户.balance 必须等于流水按时间累加的净值

$account->verifyBalance();  // bool,看是否一致
$account->getBalanceDifference();  // float,差额(0 才对)
$account->calculateBalanceFromTransactions();  // 现场重算

这是审计的核心校验。日常运行中两者必须一致;若出现不一致只可能是 bug 或人为绕过(已通过 account-state-machine 守护和 Policy 双重防御)。

与一次性收费的 CollectionOrder + Receipt 关系

保证金的每笔流水也会建一张 CollectionOrder 和 Receipt(详见 collection-order-and-receipt),退款 / 扣罚走红字 CollectionOrder(详见 red-receipt-design)。

flowchart LR
  A[业户缴款 5000] --> B[DepositTransaction<br/>type=deposit, amount=5000]
  A --> C[CollectionOrder<br/>actual=5000]
  C --> D[Receipt<br/>amount=5000]
  B -.关联.-> C

  E[退款 5000] --> F[DepositTransaction<br/>type=refund, amount=5000]
  E --> G[CollectionOrder<br/>actual=-5000 红字]
  G --> H[Receipt<br/>amount=-5000 红字]
  F -.关联.-> G

为什么不只用 DepositTransaction?因为业户要拿到一张可下载、可打印的收据凭证 —— 那是 Receipt 的职责。DepositTransaction 是内部台账,Receipt 是对外凭证。

业户视角(您看到什么)

业户通常不直接接触账户/流水概念。您看到的是:

  • 物业前台告诉您"您还有 ¥5,000 装修保证金在账"
  • 装修完了物业给您一张红字收据:"装修保证金退还 ¥-5,000"
  • 微信小程序"我的账户"里能查到余额和历次变动

底下的两个对象都是后台的事。

业务人员视角

后台 → 保证金 → 账户列表,你看到的每行就是一个 DepositAccount。点开"查看"进入 ViewDepositAccount,右侧的"流水"标签就是该账户的 DepositTransaction 列表(只读、按时间倒序)。

所有写入操作(DepositAction / RefundAction / ForfeitureAction 等)都同时写账户余额 + 流水,事务内完成。任何只写一边的代码都是 bug。

相关文档