《独立开发者的商业指南·收入与财务工程》3.3 资产负债表:应收、递延收入与权益

资产负债表是某一时点的快照。本节用 LedgerLite 的期末表逐项校验资产等于负债加权益,拆开应收、递延收入与权益三个关键科目,再用期初表倒推和三表勾稽证明利润表与现金流量表如何落到同一张表上,并对照 Tidecast 与 Nord 的科目差异。

以下情境为教学假设,人物与数字不代表经核实的真实案例。

利润表看一年,现金流量表看钱的进出,资产负债表看某一时点还剩什么。三张表里,资产负债表最像结果:前两张表的每一笔变化,最后都要落到资产、负债或权益的某个科目上。如果一张资产负债表能平衡,不代表账一定对;但如果它不平衡,前面两张表一定有一处没接上。

LedgerLite 的期末表只有六个科目:现金 95,000、应收 12,000、固定资产 3,000、递延收入 22,000、应付 8,000、权益 80,000。科目少,反而适合把三表勾稽的每一步看清楚。Tidecast 和 Nord Studio 没有完整资产负债表,但它们的应收与递延收入结构足够说明买断、订阅与服务三种生意的差异。

资产 = 负债 + 权益

资产负债表的基本恒等式是:

资产 = 负债 + 权益

资产是公司拥有的资源:现金、应收、设备。负债是欠别人的义务:递延收入、应付账款、借款。权益是资产减去负债后的剩余,属于所有者。恒等式不是一条需要「配平」的规则,而是复式记账的自然结果:每一笔交易至少影响两个科目,影响过后两边仍然相等。

LedgerLite 的期末表如下:

资产金额负债与权益金额
现金$95,000递延收入$22,000
应收$12,000应付$8,000
固定资产$3,000权益$80,000
合计$110,000合计$110,000

六个科目各有来源。现金 95,000 来自 3.2 节的期末现金;应收 12,000 是已经确认但还没收到的收入;固定资产 3,000 是当年 3,000 美元设备投资,因为假设没有折旧,账面价值等于原值;递延收入 22,000 是已经收到但还没确认的收入;应付 8,000 是已经发生但还没支付的费用;权益 80,000 是资产减负债后的剩余。

这张表是简化表,不是法定报表。它没有存货、没有无形资产、没有借款、没有税款应收应付,也没有汇兑调整。简化假设是:没有折旧、没有利息、没有汇兑损益;没有分红;应付账款不变。只有在这组假设下,六个科目才能把三张表完整闭合。

应收与递延收入:两个方向的时间差

应收和递延收入是一对镜像科目:一个先确认后收款,一个先收款后确认。把它们放在一起看,才能理解营运资金为什么会是负的。

应收:已经确认但还没收到的钱

应收是利润表和现金流量表之间的第一个时间差。LedgerLite 在年内确认了 240,240 美元收入,但年末还有 12,000 美元没收到。这 12,000 不是坏账,也不是现金,而是一项资产:客户欠公司的钱。

案例事实表给了四个关于应收的数字:平均账期 Net 15;年末应收 12,000 美元,约 18 天收入;逾期 30 天以上占应收 6%;坏账准备 1%。把它们换成可复算的指标:

指标公式结果
应收周转天数$12,000 ÷ $240,240 × 36518.2 天
应收相当于几个月 MRR$12,000 ÷ $20,0200.60 个月
逾期 30 天以上金额$12,000 × 6%$720
坏账准备$12,000 × 1%$120
净应收$12,000 − $120$11,880

18.2 天比 Net 15 的合同账期长约 3 天,说明年末有一部分款项在账期内但尚未到期,也有一部分已经逾期。6% 的逾期金额是 720 美元,1% 的坏账准备是 120 美元。案例的简化资产负债表按应收总额 12,000 列示,没有单列坏账准备;如果按净额列示,资产会减少 120,权益也会相应减少 120,恒等式仍然成立,但表上需要多一个「坏账准备」的 contra-asset 科目。本节沿用案例表的总额口径,不另设准备科目。

应收的变化方向也要和现金流量表对上。3.2 节说应收增加 2,000,所以期初应收是 12,000 − 2,000 = 10,000。应收增加 2,000 意味着当年确认的收入比收到的现金多 2,000,经营现金流因此减少 2,000。这个 2,000 不是损失,只是时间差;如果客户按 Net 15 付款,下一年它会变成现金。

把三个案例的应收放在一起,能看到账期结构:

案例应收占年收入隐含天数合同账期说明
LedgerLite5.0%18.2 天Net 15订阅客户,年末应收 $12,000
Tidecast0%0 天平台月结 30 天年末已结算,案例按 0 应收处理
Nord Studio7.3%26.6 天Net 30服务为主,回款慢于 LedgerLite

Nord 的 7.3% 乘以 365 等于 26.6 天,接近 Net 30 的账期;LedgerLite 的 5.0% 乘以 365 等于 18.2 天,接近 Net 15。账期越长,应收占收入的比例越高,现金被客户占用的时间也越长。Tidecast 是买断制,平台月结 30 天,但案例把年末应收按 0 处理,说明它的现金节奏主要由销量和平台结算决定,而不是由客户账期决定。

应收账龄、催收节奏和坏账准备的详细处理属于卷二《合同、应收与风险》的内容,那里会展开账龄表与催收节奏;本节只把应收作为资产负债表的一个科目,确认它和经营现金流的符号关系。

递延收入:已经收到但还没确认的钱

递延收入是第二个时间差,方向和应收相反。LedgerLite 的年付客户在年初支付全年费用,但公司只能按月确认收入;还没确认的部分就是递延收入。它是一项负债,因为公司还欠客户服务。

期末递延收入是 22,000 美元,期初是 14,000 美元,增加 8,000 美元。这个增加额在 3.2 节的经营现金流里是加项:客户先付钱,现金比收入多,所以要把 8,000 加回。它在资产负债表上则是负债增加 8,000:公司未来要交付对应服务。

指标公式结果
期末递延收入案例表$22,000
期初递延收入$22,000 − $8,000$14,000
递延收入相当于几个月 MRR$22,000 ÷ $20,0201.10 个月
递延收入占年收入$22,000 ÷ $240,2409.2%

1.10 个月 MRR 说明期末递延收入大约是 1.1 个月的订阅收入。这个数字不需要和年付比例直接对应:年付客户占 30%,但年付订单的确认节奏、续费时点和退款条款都会影响期末余额。案例只给出 22,000 的期末值,本节不把它反推成客户数或年付金额。

递延收入让 LedgerLite 的营运资金变成负数:

营运资金 = 应收 − 递延收入 − 应付
         = 12,000 − 22,000 − 8,000
         = −18,000

负营运资金不是坏事,它意味着客户预收在给生意融资:公司先拿到现金,再按月交付服务。但它也不是免费的:递延收入是一笔必须履约的负债,如果客户流失、退款增加或年付比例下降,这笔负债会收缩,经营现金流会比净利润更早变差。

三个案例的营运资金方向不同:

案例递延收入应收营运资金方向谁在给生意融资
LedgerLite$22,000$12,000负,−$18,000客户预收
Tidecast$0$0接近 0无,现款或平台月结
Nord Studio案例未给出占年收入 7.3%偏正开发者垫资

Tidecast 是买断制,售出即确认,没有预收义务,也没有应收,所以它的营运资金接近 0;现金节奏由销量和平台结算决定。Nord 是服务加产品:服务按 Net 30 开票,形成应收;产品按月订阅,是否形成递延收入取决于收款时点,案例没有给出余额。方向上看,Nord 更可能是「开发者先垫资」,而不是「客户先预收」。

预收、递延与确认时点的具体规则见 4.1 预收、递延与确认时点 ;本节只确认递延收入是负债,且它的增加是经营现金流的加项。

权益:资产减去负债后的剩余

权益是资产负债表上最容易被误解的科目。它不是现金,也不是「老板能拿走的钱」,而是资产减去负债后的剩余。LedgerLite 的期末权益是 80,000 美元:

权益 = 资产 − 负债
     = 110,000 − (22,000 + 8,000)
     = 80,000

权益的期初值可以从期初表倒推。3.2 节已经算出期初现金 33,701、期初应收 10,000、期初固定资产 0、期初递延收入 14,000、期初应付 8,000,所以:

期初资产 = 33,701 + 10,000 + 0 = 43,701
期初负债 = 14,000 + 8,000 = 22,000
期初权益 = 43,701 − 22,000 = 21,701

从期初权益到期初权益加净利润,正好得到期末权益:

权益桥金额来源
期初权益$21,701期初资产 $43,701 − 期初负债 $22,000
加净利润+$58,299利润表
减分红$0案例假设无分红
期末权益$80,000资产负债表

这里有两个容易混淆的点。第一,创始人薪酬 60,000 是利润表里的费用,不是分红;它已经通过净利润减少了权益,不能再从权益里减一次。第二,权益 80,000 不等于现金 95,000:公司还有 12,000 应收、3,000 固定资产和 30,000 负债,权益是这些科目共同作用后的剩余,不是某个银行账户的余额。

如果当年有分红,权益桥会多一项「减分红」,现金和权益会同时减少;案例假设没有分红,所以权益变化只来自净利润 58,299。这个假设让三表闭环更干净,也让读者能把注意力放在营运资金和资本开支上。

从期初到期末:三表闭环

把期初表和期末表放在一起,每一项变化都能在利润表或现金流量表里找到来源:

科目期初本期变化期末变化来源
现金$33,701+$61,299$95,000现金流量表净现金增加
应收$10,000+$2,000$12,000收入确认多于收款
固定资产$0+$3,000$3,000设备投资
递延收入$14,000+$8,000$22,000预收多于确认
应付$8,000$0$8,000假设不变
权益$21,701+$58,299$80,000净利润,无分红
资产合计$43,701+$66,299$110,000现金、应收、固定资产变化之和
负债与权益合计$43,701+$66,299$110,000递延收入与权益变化之和

期初表和期末表都平衡:

期初:43,701 = 22,000 + 21,701
期末:110,000 = 30,000 + 80,000

资产侧增加 66,299,等于现金增加 61,299 加应收增加 2,000 加固定资产增加 3,000;负债与权益侧增加 66,299,等于递延收入增加 8,000 加权益增加 58,299。两边增加额相等,不是巧合,而是因为每一笔变化都同时影响两侧:确认收入增加应收或现金,预收增加现金和递延收入,设备投资增加固定资产并减少现金,净利润增加权益并对应资产或负债的变化。

三张表的分工可以用一张表总结:

表关键数字如何进入资产负债表
利润表净利润 $58,299权益增加 $58,299
现金流量表净现金增加 $61,299现金增加 $61,299
资产负债表应收 +$2,000、递延收入 +$8,000、固定资产 +$3,000对应资产与负债科目

这张表也说明了为什么三表必须一起看。只看资产负债表,80,000 权益看起来很多,但资产里有 12,000 是应收,负债里有 22,000 是未来要交付的服务;只看利润表,58,299 净利润看起来不错,但现金增加了 61,299,差额来自预收和应收;只看现金流量表,61,299 净增加看起来健康,但没有说明这笔钱对应多少负债。

简化假设在这里起作用:没有折旧,所以固定资产从 0 到 3,000 只受资本开支影响;没有利息,所以权益变化只来自经营;没有汇兑,所以没有重估调整;没有分红,所以权益桥只有净利润一项。真实报表里,这些项目会各占一行,但勾稽逻辑不变。

把资产负债表写成代码

下面的 balance.ts 做三件事:校验资产等于负债加权益,计算两种营运资金口径,提供权益桥和递延收入、应收的差额函数。金额用整数美分,资产与负债科目必须是非负整数,权益在累计亏损时可以为负;不平衡时返回差额,而不是抛错,方便调用方打印完整的校验结果。

// file: src/fin/balance.ts
// tier: L1
// verify: node --test test/fin/balance.test.ts

import { type Cents, add, sub } from "../core/money.ts";
import { type Result, fail, ok } from "../core/result.ts";

export type BalanceSheetInput = {
  cash: Cents;
  receivables: Cents;
  fixedAssets: Cents;
  deferredRevenue: Cents;
  payables: Cents;
  equity: Cents;
};

export type BalanceCheck = {
  totalAssets: Cents;
  totalLiabilities: Cents;
  totalEquity: Cents;
  liabilitiesAndEquity: Cents;
  difference: Cents;
  balanced: boolean;
  workingCapital: Cents;
  operatingWorkingCapital: Cents;
};

function nonNegative(value: Cents, label: string): Result<true> {
  if (!Number.isInteger(value) || value < 0) {
    return fail(`${label} must be a non-negative integer`);
  }
  return ok(true);
}

/**
 * Checks assets = liabilities + equity and reports two working-capital views:
 *   working capital           = cash + receivables - deferred - payables
 *   operating working capital = receivables - deferred - payables
 * The second view removes cash, which is the point of the first view, so it
 * shows whether customers or suppliers are funding the operating cycle.
 * Asset and liability accounts must be non-negative; equity may be negative
 * when accumulated losses exceed contributed capital.
 */
export function checkBalanceSheet(
  input: BalanceSheetInput,
): Result<BalanceCheck> {
  const fields: Array<[Cents, string]> = [
    [input.cash, "cash"],
    [input.receivables, "receivables"],
    [input.fixedAssets, "fixed assets"],
    [input.deferredRevenue, "deferred revenue"],
    [input.payables, "payables"],
  ];
  for (const [value, label] of fields) {
    const checked = nonNegative(value, label);
    if (!checked.ok) {
      return checked;
    }
  }
  if (!Number.isInteger(input.equity)) {
    return fail("equity must be an integer number of cents");
  }
  const totalAssets = add(add(input.cash, input.receivables), input.fixedAssets);
  const totalLiabilities = add(input.deferredRevenue, input.payables);
  const liabilitiesAndEquity = add(totalLiabilities, input.equity);
  const difference = sub(totalAssets, liabilitiesAndEquity);
  return ok({
    totalAssets,
    totalLiabilities,
    totalEquity: input.equity,
    liabilitiesAndEquity,
    difference,
    balanced: difference === 0,
    workingCapital: sub(
      add(input.cash, input.receivables),
      totalLiabilities,
    ),
    operatingWorkingCapital: sub(
      sub(input.receivables, input.deferredRevenue),
      input.payables,
    ),
  });
}

/** Ending equity = beginning equity + net income - distributions. */
export function equityBridge(
  beginningEquity: Cents,
  netIncome: Cents,
  distributions: Cents = 0,
): Result<Cents> {
  if (!Number.isInteger(beginningEquity)) {
    return fail("beginning equity must be an integer number of cents");
  }
  if (!Number.isInteger(netIncome)) {
    return fail("net income must be an integer number of cents");
  }
  const paid = nonNegative(distributions, "distributions");
  if (!paid.ok) {
    return paid;
  }
  return ok(sub(add(beginningEquity, netIncome), distributions));
}

/** Cash received before it is recognized: prepaid minus recognized revenue. */
export function deferredRevenue(
  prepaidCents: Cents,
  recognizedCents: Cents,
): Result<Cents> {
  const prepaid = nonNegative(prepaidCents, "prepaid amount");
  if (!prepaid.ok) {
    return prepaid;
  }
  const recognized = nonNegative(recognizedCents, "recognized revenue");
  if (!recognized.ok) {
    return recognized;
  }
  if (recognizedCents > prepaidCents) {
    return fail("recognized revenue cannot exceed prepaid amount");
  }
  return ok(sub(prepaidCents, recognizedCents));
}

/** Invoiced but not collected: invoiced minus collected. */
export function receivables(
  invoicedCents: Cents,
  collectedCents: Cents,
): Result<Cents> {
  const invoiced = nonNegative(invoicedCents, "invoiced amount");
  if (!invoiced.ok) {
    return invoiced;
  }
  const collected = nonNegative(collectedCents, "collected amount");
  if (!collected.ok) {
    return collected;
  }
  if (collectedCents > invoicedCents) {
    return fail("collected amount cannot exceed invoiced amount");
  }
  return ok(sub(invoicedCents, collectedCents));
}

checkBalanceSheet 的输出包含资产合计、负债合计、权益、负债加权益、差额、是否平衡,以及两个营运资金口径。workingCapital 把现金算进去,等于现金加应收减递延收入减应付;operatingWorkingCapital 把现金排除,只看应收、递延收入和应付,回答「客户和供应商谁在给运营周期融资」。LedgerLite 的两个值分别是 77,000 和 −18,000:前者是短期偿债视角,后者是运营资金结构视角。

equityBridge 把期初权益、净利润和分红串起来:21,701 + 58,299 − 0 = 80,000。deferredRevenue 和 receivables 分别计算「预收减确认」和「开票减收款」,它们是资产负债表上两个时间差科目的最小模型。LedgerLite 的输入是现金 9,500,000 美分、应收 1,200,000、固定资产 300,000、递延收入 2,200,000、应付 800,000、权益 8,000,000;输出资产合计 11,000,000、负债合计 3,000,000、差额 0。

代码不处理坏账准备、折旧、税款应收应付和汇兑调整。它只覆盖本章的简化口径;科目设置、月结和审计调整属于操作层流程,见 记账与月结 。

小结

  • 资产负债表是时点快照:LedgerLite 期末资产 110,000 = 负债 30,000 + 权益 80,000。
  • 应收 12,000 是已确认未收款,约 18.2 天收入;6% 逾期超过 30 天对应 720,坏账准备 1% 对应 120。
  • 递延收入 22,000 是已收款未确认,约 1.1 个月 MRR;它让营运资金变成 −18,000,客户预收在给生意融资。
  • 权益 80,000 是资产减负债的剩余,不是现金;期初权益 21,701 加净利润 58,299 等于期末 80,000(无分红)。
  • 期初表可以由期末表和现金流倒推:现金 33,701、应收 10,000、固定资产 0、递延收入 14,000、应付 8,000、权益 21,701。
  • 三表闭环:净利润进权益,净现金增加进现金,应收、递延收入和固定资产各自找到对应科目;无折旧、无利息、无汇兑是闭环成立的前提。

阅读导航:上一节:3.2 现金流量表:经营、投资、筹资 · 下一节:4.1 预收、递延与确认时点 。

常见错误与边界

  1. 把权益当现金。 LedgerLite 权益 80,000、现金 95,000,两者不相等;权益还要扣掉 22,000 递延收入和 8,000 应付,再加上 12,000 应收和 3,000 固定资产。
  2. 把递延收入当收入。 递延收入是负债,不是当期收入;它增加时现金比收入多,所以在现金流量表里加回,在资产负债表上记负债。
  3. 把应收当现金。 应收是资产,不是现金;应收增加 2,000 意味着经营现金流减少 2,000,而不是增加。
  4. 忘记期初表。 期末现金 95,000 需要期初 33,701 加净现金增加 61,299 才能解释;只列期末表,无法验证现金流。
  5. 用总额应收忽略坏账准备。 案例表按 12,000 总额列示;如果按 1% 计提坏账准备,净应收是 11,880,资产和权益各减少 120,表上要多一个准备科目。
  6. 把创始人薪酬当分红。 薪酬是利润表费用,已经通过净利润减少权益;分红是权益分配,会同时减少现金和权益。两者不能混为一谈。
  7. 把固定资产当费用。 设备投资 3,000 是投资现金流,形成固定资产;本节假设无折旧,所以固定资产账面价值不下降。真实报表里折旧会减少资产和权益。
  8. 忽略营运资金的符号。 应收增加占用现金,递延收入和应付增加提供现金;符号反了,经营现金流和资产负债表会对不上。
  9. 用不同舍入口径。 案例表用整数美元,代码用精确美分;税额和现金流的 0.20 美元差异如果处理不一致,期末现金会出现几分钱的不平衡。
  10. 认为资产负债表平衡就说明账对。 平衡只说明恒等式成立;科目分类错误、收入确认时点错误、漏记负债,都可能让一张平衡的表仍然是错的。三表要一起看。

本节的边界是「简化资产负债表的勾稽」:只覆盖现金、应收、固定资产、递延收入、应付和权益六个科目,不处理坏账准备、折旧、利息、汇兑、借款、税款应收应付和分红。它不涉及记账软件操作、发票模板和税务申报流程;这些属于操作层与税务章节。把这张表闭合之后,第 4 章会单独展开递延收入与收入质量,第 13 章会把三张表横向对照,回到「三个案例为什么估值不同」的主线。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「books」更多文章

  1. 《移动游戏产品的架构·商业化与发行工程》附录 C 商业化与发行评审清单
  2. 《移动游戏产品的架构·商业化与发行工程》附录 B 双案例商业化事实表
  3. 《移动游戏产品的架构·商业化与发行工程》附录 A 商业化与发行术语速查