以下情境为教学假设,人物与数字不代表经核实的真实案例。
利润表按权责发生制确认收入与费用,现金流量表按收付实现制记录钱的进出。两者之间的差不是记账错误,而是三种时间差:客户先付钱后确认、先确认后收钱、以及买设备这类不影响利润的支出。三表建模的第二张表,就是把这些时间差逐项列出来,让净利润走到现金。
LedgerLite 是最好的主线,因为它的三张表能完整闭合:净利润 58,299,经营现金流 64,299,净现金增加 61,299,期末现金 95,000。Tidecast 和 Nord Studio 只提供部分现金流信息,但它们的差异足够说明买断和服务在现金节奏上的不同。
三类现金流
现金流量表把现金分成三类。经营现金流是生意本身产生的现金:客户回款、供应商付款、员工薪酬、所得税。投资现金流是长期资产的买卖:设备、软件、资本化开发。筹资现金流是资本结构的变化:借款、还款、股东投入、分红。
三个案例在这三类上的分布很不相同:
| 类别 | 主要流入 | 主要流出 | LedgerLite 本年 | Tidecast 可建模部分 | Nord 可建模部分 |
|---|---|---|---|---|---|
| 经营 | 客户回款 | 薪酬、税、供应商 | +$64,299 | +$92,090 | +$25,740(上限) |
| 投资 | 资产出售 | 设备、资本化开发 | −$3,000 | 未给出,按 $0 | 未给出,按 $0 |
| 筹资 | 借款、增资 | 还款、分红 | $0 | 未给出,按 $0 | 未给出,按 $0 |
| 净现金增加 | +$61,299 | +$92,090 | +$25,740(上限) |
LedgerLite 的 64,299 是完整经营现金流:SDE 130,240 减创始人薪酬 60,000、减所得税 11,941,再加递延收入增加 8,000、减应收增加 2,000。投资现金流只有一笔 3,000 的设备支出。筹资现金流为 0,因为案例没有借款、增资或分红。
Tidecast 的 92,090 是 SDE 121,171 减所得税 29,081 的结果。案例事实表说它的应收占年收入 0%,平台月结 30 天但年末按已结算处理,所以没有应收和递延收入的调整;案例也没有给出资本开支,按 0 处理。这个 92,090 是「可建模部分」,不是经过完整营运资金调整的经营现金流。
Nord Studio 的 25,740 同样是 SDE 34,320 减所得税 8,580。它的应收占年收入 7.3%,服务按 Net 30 开票,产品按月收款;案例没有给出应收余额的变化,也没有给出资本开支。因此 25,740 只能理解为「没有应收变化时的上限」,不能直接称为完整经营现金流。
| 案例 | SDE | 减所得税 | 可建模现金 | 还缺什么 |
|---|---|---|---|---|
| LedgerLite | $130,240 | −$11,941 | $64,299(经营现金流) | 已含递延收入与应收变化 |
| Tidecast | $121,171 | −$29,081 | $92,090 | 资本开支、年末应收余额未给出 |
| Nord Studio | $34,320 | −$8,580 | $25,740 | 应收变化、递延收入、资本开支未给出 |
本节对三案例统一采用简化假设:没有折旧、没有利息、没有汇兑损益;没有借款和分红;LedgerLite 的应付账款不变。这些假设让三张表能用整数美元闭合,也让「利润到现金」的桥只剩营运资金和资本开支两部分。
为什么净利润不等于经营现金流
把净利润调到经营现金流,有两种等价写法:从净利润出发,或从 SDE 出发。本节用 SDE,因为案例事实表先给出 SDE,再减薪酬和税,路径更短。
净利润 = SDE − 创始人薪酬 − 所得税
经营现金流 = 净利润 + 递延收入增加 − 应收增加 + 应付增加
LedgerLite 代入后是:
净利润 = 130,240 − 60,000 − 11,941 = 58,299
经营现金流 = 58,299 + 8,000 − 2,000 + 0 = 64,299
这两个调整项的方向很容易记反。递延收入是「已经收到、还没确认」的钱,它增加时,现金比收入多,所以要加回;应收是「已经确认、还没收到」的钱,它增加时,收入比现金多,所以要减去。应付是「已经发生、还没支付」的费用,它增加时,现金比费用多,所以要加回。
| 调整项 | 对现金的方向 | LedgerLite | 原因 |
|---|---|---|---|
| 递延收入增加 | 加 | +$8,000 | 预收多于当期确认 |
| 应收增加 | 减 | −$2,000 | 当期确认多于收款 |
| 应付增加 | 加 | $0 | 案例假设应付不变 |
| 折旧与摊销 | 加 | $0 | 非现金费用;本节假设无折旧 |
| 利息费用 | 减 | $0 | 简化假设无利息 |
| 汇兑损益 | 加减 | $0 | 简化假设无汇兑 |
如果没有这 8,000 和 2,000,经营现金流会正好等于净利润 58,299。有了它们,经营现金流是 64,299,比净利润高 6,000(64,299 − 58,299)。这个 6,000 不是「多赚的钱」,而是「客户预收减去应收占用」的净现金来源。它在资产负债表上对应递延收入负债增加 8,000、应收资产增加 2,000;3.3 节会把这两个科目接回去。
LedgerLite 现金流量表逐项复算
把 LedgerLite 从 SDE 算到净现金增加,一共八步。每一步都能用案例事实表复算。
| 步骤 | 公式 | 结果 |
|---|---|---|
| SDE | 毛利 $202,240 − 运营费用 $72,000 | $130,240 |
| 减创始人薪酬 | $130,240 − $60,000 | $70,240 |
| 减所得税 | $70,240 − $11,941 | $58,299 |
| 加递延收入增加 | $58,299 + $8,000 | $66,299 |
| 减应收增加 | $66,299 − $2,000 | $64,299 |
| 经营现金流 | $64,299 | |
| 减设备投资 | $64,299 − $3,000 | $61,299 |
| 净现金增加 | $61,299 |
这里同样有舍入差。案例表按整数美元展示,所以税额是 11,941、经营现金流是 64,299、净现金增加是 61,299;如果按美分精确计算,税额是 11,940.80,经营现金流是 64,299.20,净现金增加是 61,299.20。本节的表格用整数美元,代码用精确到分的美分,两者相差不超过 0.20 美元。
现金的期初与期末也能接上:
| 项 | 金额 | 公式 |
|---|---|---|
| 期初现金 | $33,701 | 期末现金 $95,000 − 净现金增加 $61,299 |
| 加经营现金流 | +$64,299 | 来自上表 |
| 减设备投资 | −$3,000 | 投资活动 |
| 加筹资现金流 | $0 | 无借款、无增资、无分红 |
| 期末现金 | $95,000 | 期初 + 经营 + 投资 + 筹资 |
期初现金 33,701 不是案例事实表直接给出的数字,而是由期末现金 95,000 和净现金增加 61,299 倒推出来的。这个倒推值会在 3.3 节用来校验期初资产负债表:期初资产 43,701 减去期初负债 22,000,正好等于期初权益 21,701。
营运资金变化的方向
营运资金变化是经营现金流里最容易出错的部分。把四个常见科目放在一起,方向就清楚了:
| 科目 | 增加意味着 | 对现金 | LedgerLite 本年 |
|---|---|---|---|
| 应收 | 确认收入但未收款 | 减 | +$2,000,现金 −$2,000 |
| 递延收入 | 收款但未确认 | 加 | +$8,000,现金 +$8,000 |
| 应付 | 费用或采购未付 | 加 | $0 |
| 存货 | 采购但未售出 | 减 | 不适用,无存货 |
LedgerLite 的营运资金是负的:应收 12,000 减递延收入 22,000 再减应付 8,000,等于 −18,000。负营运资金意味着客户在给生意融资:年付客户先付一年,递延收入比应收多,现金比利润表更宽裕。这是订阅 SaaS 的结构性优势,但也不是无条件的:如果年付比例下降、月流失上升,递延收入会收缩,经营现金流会比净利润更早变差。
Tidecast 没有应收和递延收入。它的现金节奏由销量决定:月均 800 份、12 月 2,400 份、1 月 480 份,Q4 占全年销量 38%。平台月结 30 天意味着 12 月的销售要到 1 月才到账,而 1 月的销量只有 480 份。现金在年初可能很紧,尽管全年净利润是 92,090。
Nord Studio 的应收占年收入 7.3%,服务按 Net 30 开票,产品按月收款。服务收入占 72.7%,续约率 70%;如果应收增加,经营现金流会低于 SDE 减税。案例没有给出应收变化,所以本节只把 25,740 当作上限,不把它写成完整经营现金流。
投资、筹资与三表勾稽
投资活动在 LedgerLite 里只有一笔 3,000 美元的设备支出。因为本节假设没有折旧,固定资产从期初 0 增加到期末 3,000,正好等于资本开支。如果存在折旧,资本开支和折旧就要分开:资本开支是投资现金流,折旧是非现金费用,要在间接法里加回。
筹资活动为 0。案例没有借款、没有增资、没有分红,所以筹资现金流是 0,期末权益的变化只来自净利润。这个假设让权益桥变得很简单:
期末权益 = 期初权益 + 净利润 − 分红
80,000 = 21,701 + 58,299 − 0
三张表的勾稽可以放在一张表里:
| 勾稽项 | 利润表 | 现金流量表 | 资产负债表 |
|---|---|---|---|
| 净利润 | $58,299 | 经营现金流起点 | 权益增加 $58,299 |
| 递延收入增加 | 不影响当期收入 | 经营现金流 +$8,000 | 递延收入负债 +$8,000 |
| 应收增加 | 已确认收入 | 经营现金流 −$2,000 | 应收资产 +$2,000 |
| 设备投资 | 不影响当期利润 | 投资现金流 −$3,000 | 固定资产 +$3,000 |
| 净现金增加 | +$61,299 | 期末现金 $95,000 | |
| 权益桥 | 净利润 $58,299 | 期末权益 $80,000 |
这张表说明三表不是三套独立的数字,而是同一组交易的三次投影。利润表里的净利润 58,299,进入现金流量表成为经营现金流的起点,进入资产负债表成为权益的增加;递延收入、应收、固定资产则在两张表里各出现一次。勾稽成立的条件是:每一笔变化都能在另一张表里找到对应科目,且没有遗漏的折旧、利息、汇兑或分红。
更长期的现金压力测试不在本节展开。13 周现金流、情景分析和现金跑道底线见 8.1 13 周现金流表 ;本节只建立年度三表的静态勾稽。
把现金流写成代码
下面的 cashflow.ts 把 SDE、薪酬、税、营运资金变化、资本开支和筹资输入固化成一条可复算的链路。金额用整数美分,符号约定写在类型和注释里:递延收入增加为正、应收增加为正、应付增加为正;经营现金流自动把应收的增加转成现金占用。
// file: src/fin/cashflow.ts
// tier: L1
// verify: node --test test/fin/cashflow.test.ts
import { type Cents, add, sub } from "../core/money.ts";
import { type Result, fail, ok } from "../core/result.ts";
export type WorkingCapitalChange = {
deferredRevenueChange: Cents;
receivablesChange: Cents;
payablesChange?: Cents;
};
export type CashflowInput = {
sde: Cents;
founderSalary: Cents;
incomeTax: Cents;
workingCapital: WorkingCapitalChange;
capex: Cents;
financing?: Cents;
};
export type Cashflow = {
netIncome: Cents;
workingCapitalImpact: Cents;
operatingCashFlow: Cents;
investingCashFlow: Cents;
financingCashFlow: Cents;
netCashChange: Cents;
};
function validate(input: CashflowInput): Result<Cents> {
if (!Number.isInteger(input.sde)) {
return fail("SDE must be an integer number of cents");
}
if (!Number.isInteger(input.founderSalary) || input.founderSalary < 0) {
return fail("founder salary must be a non-negative integer");
}
if (!Number.isInteger(input.incomeTax) || input.incomeTax < 0) {
return fail("income tax must be a non-negative integer");
}
if (!Number.isInteger(input.capex) || input.capex < 0) {
return fail("capex must be a non-negative integer");
}
const payablesChange = input.workingCapital.payablesChange ?? 0;
const changes = [
input.workingCapital.deferredRevenueChange,
input.workingCapital.receivablesChange,
payablesChange,
input.financing ?? 0,
];
for (const change of changes) {
if (!Number.isInteger(change)) {
return fail("working capital and financing changes must be integers");
}
}
return ok(payablesChange);
}
/**
* Indirect cash flow with three buckets:
* net income = SDE - founder salary - income tax
* operating = net income + deferred revenue change - receivables change
* + payables change
* investing = -capex
* financing = explicit financing inflow (or outflow when negative)
* A rise in deferred revenue and payables is a cash source; a rise in
* receivables is a cash use.
*/
export function buildCashflow(input: CashflowInput): Result<Cashflow> {
const checked = validate(input);
if (!checked.ok) {
return checked;
}
const payablesChange = checked.value;
const netIncome = sub(sub(input.sde, input.founderSalary), input.incomeTax);
const workingCapitalImpact = sub(
add(input.workingCapital.deferredRevenueChange, payablesChange),
input.workingCapital.receivablesChange,
);
const operatingCashFlow = add(netIncome, workingCapitalImpact);
const investingCashFlow = sub(0, input.capex);
const financingCashFlow = input.financing ?? 0;
const netCashChange = add(
add(operatingCashFlow, investingCashFlow),
financingCashFlow,
);
return ok({
netIncome,
workingCapitalImpact,
operatingCashFlow,
investingCashFlow,
financingCashFlow,
netCashChange,
});
}
代码的推导顺序是:先算净利润,再把营运资金影响加到净利润上得到经营现金流,最后加上投资和筹资得到净现金增加。receivablesChange 传正数表示应收增加,代码内部做减法;deferredRevenueChange 和 payablesChange 传正数表示负债增加,代码内部做加法。这个符号约定如果不写清楚,调用方很容易把方向弄反。
LedgerLite 的输入是 SDE 13,024,000 美分、薪酬 6,000,000、税 1,194,080、递延收入增加 800,000、应收增加 200,000、资本开支 300,000、筹资 0。输出是净利润 5,829,920、营运资金影响 600,000、经营现金流 6,429,920、投资现金流 −300,000、净现金增加 6,129,920。四舍五入到美元就是 58,299、64,299 和 61,299。
这套代码不处理折旧、摊销、利息、汇兑、税款的应收应付,也不处理多币种换算。它只覆盖本章的简化口径;银行流水导入、收款核销和月结对账属于操作层流程,见 收款、开票与对账 。
小结
- 现金流量表分三类:经营、投资、筹资。LedgerLite 只有经营现金流和一笔 3,000 美元设备投资,筹资为 0。
- 净利润 58,299 到经营现金流 64,299 的桥是加递延收入增加 8,000、减应收增加 2,000;没有折旧、利息、汇兑。
- 经营现金流 64,299 减资本开支 3,000 等于净现金增加 61,299;期初现金 33,701,期末现金 95,000。
- 营运资金的方向:应收增加是现金占用,递延收入和应付增加是现金来源。LedgerLite 的营运资金是 −18,000,客户预收在给生意融资。
- Tidecast 的可建模现金是 92,090,但没有应收和递延收入,现金高度依赖 Q4 销量;Nord 的 25,740 只是上限,因为应收变化未给出。
- 现金流量表把利润表的净利润接到资产负债表的现金和权益,是 3.3 节做期末平衡校验的前置。
阅读导航:上一节:3.1 利润表:收入、成本、费用的口径 · 下一节:3.3 资产负债表:应收、递延收入与权益 。
常见错误与边界
- 用净利润直接当现金。 LedgerLite 的净利润是 58,299,经营现金流是 64,299;差额来自递延收入和应收,不是利润表算错了。
- 把递延收入增加当收入。 递延收入是负债,不是收入;它增加时现金比收入多,所以在间接法里加回,但不能记进利润表顶行。
- 把应收增加当现金流入。 应收增加是「确认了收入但还没收到钱」,对现金是减法;方向反了会把经营现金流高估 4,000(68,299 − 64,299)。
- 忘记资本开支。 经营现金流 64,299 减设备投资 3,000 才是净现金增加 61,299;只看经营现金流会高估可自由支配的钱。
- 把筹资活动当经营。 借款、增资、分红不属于经营现金流;案例的筹资为 0,所以权益变化只来自净利润。
- 忽略平台账期与季节性。 Tidecast 的平台月结 30 天、Q4 占销量 38%;全年利润为正,不代表 1 月现金不紧。
- 把 Nord 的 25,740 当完整经营现金流。 它的应收占年收入 7.3%,服务 Net 30;应收变化未给出,25,740 只是上限。
- 把折旧当现金支出。 折旧是非现金费用,间接法要加回;本节假设无折旧,所以没有这一项,但真实账目里不能漏。
- 把税额舍入差带进三表。 精确经营现金流是 64,299.20,案例表写 64,299;三张表要用同一套舍入口径,否则期末现金会对不上。
- 忘记期初现金。 期末现金 95,000 是期初 33,701 加净现金增加 61,299 的结果;只算本期流量,无法校验资产负债表。
本节的边界是「年度、简化、无融资」的现金流模型:不处理折旧、利息、汇兑,不处理借款与分红,不处理税款的应收应付。它足够回答「利润有没有变成现金」,但不足以回答「哪个月会断粮」。后者需要 13 周滚动现金流和情景分析;操作层的银行流水导入、收款核销与月结,不在本节的建模范围内。下一节把期末现金、应收、递延收入和权益放回资产负债表,完成三表的最后一张。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。