Nordlet

← 博客

Marketplace Seller Subledgers: Revenue vs Payables

A practitioner's guide to separating customer cash, platform commission, seller payables, reserves, and payouts with balanced journal entries and a working order-to-payout data model.

Nordlet Team · · 3 分钟阅读

在多边市场(marketplace)会计中,最常见的错误是将买家支付的总金额直接作为平台收入。例如,客户支付了 100 欧元,这 100 欧元进入了支付处理商账户,而有人将整个金额都记入了销售收入。账目在一段时间内看似平了,收入数据也很漂亮,直到审计师询问卖家的负债记在哪里。结果发现根本没有,因为卖家的 90 欧元从头到尾都没有被记录为应付款项。

解决方案是结构性的,而非表面修饰。一个多边市场需要一个分类账模型,从第一笔分录开始就将五个不同的资金池严格区分开:流转中的客户资金、平台佣金收入、应付卖家款项、费用以及准备金。而打款(payout)是第六个事件,它只是用于结清应付款项,本身既不是收入事件,也不是费用事件。本指南将展示如何通过平衡的会计分录和正常运转的“订单到打款”数据模型,使这些资金池保持清晰独立。

从“主要责任人与代理人”的定性开始

在涉及任何账户结构之前,平台必须先确定自己到底在销售什么。根据 ASC 606 准则,这一点需要针对每项具体的商品或服务进行评估,其结论决定了收入是以总额法还是净额法确认。平台可以在某一交易流中充当主要责任人(principal),而在另一交易流中充当代理人(agent)。

对于典型的多边市场卖家商品销售,平台通常扮演代理人角色。它负责安排将卖家的产品送达买家,不承担库存风险,其对价是收取佣金。德勤(Deloitte)关于 ASC 606 下主要责任人与代理人的指南将测试框架建立在控制权之上:履行承诺的责任、库存风险以及定价自主权是判断指标,而不是用来凌驾于底层控制权评估之上的核对清单。

之所以必须将这一结论纳入分类账的设计中(而不仅仅写在备忘录里),是因为该结论会驱动后续的每一笔分录。如果平台是代理人,那么卖家的份额在赚取的瞬间就成了负债。如果平台针对履约或质保服务充当主要责任人,那么这部分则属于平台收入。请将该定性结论作为数据存储下来:

  • principal_agent_role(主客体角色)
  • specified_good_or_service(指定的商品或服务)
  • commission_rule_id(佣金规则 ID)
  • control_assessment_version(控制权评估版本)
  • effective_from / effective_to(生效起止时间)

两年后,复核人员在查看净佣金明细行时,应该能够一目了然地看出为什么没有采用总额法。正如 BillingPlatform 在其关于 ASC 606 主要责任人与代理人的文章中所指出,“多边市场”这个标签本身并不能解决问题,控制权分析才可以。

在编写任何日记账规则之前,先定义卖家余额

“卖家余额”并不是单一的数字。一个卖家可能拥有健康的累计生命周期余额,但却没有任何可用于打款的可用资金,因为这些钱仍处于待结算状态或被扣留作准备金。如果将这些状态混为一谈,就会错误报告卖家可以提取的金额以及平台仍欠下的债务。

至少需要追踪以下状态:

  • 待定(Pending): 已赚取或已收取,但尚不符合打款条件
  • 可用(Available): 根据平台规则符合打款条件
  • 保留/准备金(Reserved): 预扣以应对预期退款、争议或拒付
  • 已打款(Paid out): 已转账或提交结算
  • 负债/欠款(Negative): 卖家欠平台的金额,可从未来收益中扣回
  • 暂记(Suspense): 已收到资金,但卖家身份或账务处理方式尚未确定

支付服务商已经对这种区分进行了建模。Stripe 将每个关联账户划分为待定余额和可用余额,并针对某些负债卖家余额保留了平台级的准备金余额。如果支付处理商进行了这种区分,分类账也必须如此,否则对账将永远无法平账。

会计科目表与至关重要的维度

一套可行的初始结构应当将清算账户、负债账户和收入账户隔离开,并在每一笔重要的过账中携带卖家维度。

用途 账户或维度 会计处理
等待结算的处理商资金 支付处理商清算账户 清算资产
已存入银行的处理商打款 银行存款 资产
已赚取但未付的卖家金额 应付卖家款项 负债
卖家级明细 seller_id 维度 负债明细,而非收入
平台佣金 佣金收入 收入
增值税或销售税 应交税费 负债
处理商手续费 支付处理费 费用
卖家准备金 准备金负债 视合同而定
退款 冲减收入或退款科目 冲销原始处理
拒付(Chargebacks) 损失、应收款或向卖家追索 取决于由谁承担损失
等待银行确认的打款 卖家打款清算账户 清算账户
未分配金额 暂记账户 临时异常处理

每一笔重要分录都应携带卖家、订单、打款批次、支付处理商、币种、法律实体、税务处理、事件类型、外部参考编号以及任何冲销关联。缺少了这些,卖家子分类账就无法证明单个余额的真实性,总分类账也无法证明总数的准确性。

你可以将子分类账实现为每个卖家一个负债账户、一个带有 seller_id 维度的汇总应付款账户,或者拆分为应付款、准备金和打款清算账户。一旦卖家数量达到几十家以上,“汇总加维度”的方法具有更好的可扩展性。请与你的会计师共同选择该模型,因为资金保障规则和当地的支付法规可能会影响资金的呈报方式。关于过账背后的底层机制,我们关于多边市场会计的双分录分类账 API一文详细介绍了该模型所依赖的分类账原语。

记录销售分录,将卖家分项与平台分项独立列示

以代理人销售为例:客户支付 100 欧元,平台佣金为 10 欧元,卖家赚取 90 欧元。在赚取佣金和卖家权益的时点:

账户 借方 贷方
支付处理商清算账户 100 欧元
应付卖家款项 - 卖家 A 90 欧元
佣金收入 10 欧元

至关重要的控制点在于:90 欧元贷记负债,而不是收入。平台确认的收入是 10 欧元。这就是 ASC 606 准则中关于代理人的多边市场示例所达到的会计结果,即平台确认其佣金而非卖家的全部销售金额。

如果税款是单独收取的,请添加应交税费行,并根据税务定性相应调减卖家或平台的金额。切勿为了图省事而将税款并入佣金或应付卖家款项中。

将支付处理商手续费排除在收入和应付款计算之外

有三样东西经常被混为一谈:平台佣金、处理商手续费和打款金额。它们是完全不同的概念,并且会影响不同的账户。

客户支付 100 欧元,佣金为 10 欧元,支付处理商扣留 3 欧元。

  • 佣金收入保持 10 欧元不变(如果合同如此规定)。
  • 3 欧元的处理商手续费属于费用。
  • 应付卖家款项为 90 欧元,除非卖家合同规定由卖家承担处理费。只有在这种情况下,应付款才会降至 87 欧元,同时向卖家收取 3 欧元的匹配费用。

如果仅仅过账最终到达银行的净额 97 欧元,就会一步到位地抹杀总销售额、佣金和手续费。我们的支付对账参考指南也强调了这一点:拆解结算明细,将处理商手续费作为费用处理,绝不能让净存款额替代收入。

将资金可用性、准备金和打款建模为独立的事件

资金在完成扣款(capture)和最终结算之间会多次变换状态。每一次状态转换都应拥有自己的分录,而且准备金绝不应该是对收入的莫名扣减。

当可用资金转入准备金时:

账户 借方 贷方
应付卖家款项 - 卖家 A 15 欧元
卖家准备金负债 15 欧元

当准备金释放时,做相反的分录冲销。卖家的总债务并未改变,改变的只是其资金状态。Stripe 的文档中记录了增加和释放准备金的交易,以及针对长期负债余额的追索转账,这也是为什么这些业务需要可识别的账户,而不是单一的网购抵扣分录。

打款则采取独立的双步处理法。在获批时:

账户 借方 贷方
应付卖家款项 - 卖家 A 90 欧元
卖家打款清算账户 90 欧元

在确认银行结算完成时:

账户 借方 贷方
卖家打款清算账户 90 欧元
银行存款 90 欧元

如果打款失败,需将清算账户冲回应付卖家款项。打款是清偿负债,而不是费用。如果将其作为费用处理,就会与已经记录了应付款的销售额产生重复计算。Stripe 将打款状态(pending、in_transit、paid、failed、canceled)以及预计到账日期与发起日期进行了区分,这些日期不应该折叠融合成单一的时间戳。

订单到打款的数据模型

子分类账基于事件运行,而不是基于应用程序当前的订单状态。每个影响卖家的事件都包含相同的信封结构:

  • seller_id、event_id、order_id
  • event_type(事件类型:sale、refund、chargeback、reserve_hold、reserve_release、payout、adjustment)
  • effective_date、posting_date(生效日期、过账日期)
  • currency、direction、gross、commission、fees、reserve(币种、方向、总额、佣金、费用、准备金)
  • refund_ref / dispute_ref(退款参考/争议参考)
  • payout_batch_id(打款批次 ID)
  • reversal_of(冲销自)
  • source_status、idempotency_key(源状态、幂等键)

通过这些事件,你可以计算出期末余额,而不是去存储一个可变的字段:

卖家期末余额
= 期初余额
+ 卖家贷项
− 卖家借项
− 打款额
± 准备金变动
± 调整额

每个外部事件都需要一个持久的幂等键,以确保重试和重复的 Webhook 不会导致卖家被重复贷记或重复打款。行之有效的模式包括:

  • 卖家日记账事件:seller_id:order_id:event_type:version
  • 打款批次:processor:payout_id
  • 处理商事件:processor:event_type:processor_event_id

Stripe 自身的 Webhook 指南警告称重复事件不可避免,因此重复检测是必不可少的。已过账的分录保持不可变。更正操作必须通过冲销分录加上更正分录来完成,并且正是你自己的事件信封承载着 reversal_of 关联链接和原因。分类账本身只保存过账结果,而不保存该链接:Nordlet 在其API 参考文档中公开了针对日记账交易的创建、获取和列表查询功能,不支持更新或删除,因此更正操作永远是一笔新的交易,而不是对旧交易的修改。

退款和拒付必须建立关联,绝不能悬空

在下周打款中体现的退款,绝不能变成附加在该打款上的一笔崭新的负销售额。请将其关联到原始交易,并保留原始的卖家分摊比例。根据合同条款:

  • 如果合同规定佣金可退,则冲销佣金
  • 如果由卖家承担退款,则借记应付卖家款项
  • 如果由平台承担退款,则借记平台损失账户
  • 在争议审理期间增加准备金,在争议解决时予以释放或核销

打款后的拒付是负债余额产生的原因。卖家的钱已经花光了,因此平台要么从未来的收益中扣回,要么自行吸收损失。该模型必须允许出现负的卖家余额,并明确定义追索规则。Adyen 的多边市场报告显示,退款和拒付会为每个账户持有人产生单独的借方行,这正是应当追求的颗粒度。

按打款批次对账,而不是按月对账

在过账之前拆解每一笔处理商结算,并且对每一笔打款进行对账,而不是将整月数据汇总:

总扣款额
− 退款
− 处理商手续费
− 拒付
± 准备金与调整额
= 净打款额

然后,验证每个卖家和币种的四个平衡点是否一致:卖家子分类账、处理商的卖家余额、打款报告以及银行清算账户。当它们不一致时,应对差异进行分类(时间差、缺失事件、重复、归属错误、币种错误、打款失败、拒付错记给其他方)。用抵消净额的方式掩盖错误,只会让错误叠加并一直延续到下一次结账。

汇总整个月的账目会让时间差相互抵消,从而掩盖真正的断层。通过打款 ID 和交易参考编号(而不是金额和日期)进行按打款批次匹配,能够及时发现这些问题。

常见的故障模式

故障模式 危害所在 控制措施
客户支付总额被记录为收入 虚增收入,掩盖卖家负债 在赚取时点的事件中分别记录应付款和佣金
仅入账净存款额 丢失总额、手续费、退款、准备金 拆解每一笔结算
打款被记为费用 错误表述负债的清偿 打款时借记应付卖家款项
只有一个卖家余额字段 混淆了待定、可用、准备金和已付状态 显式追踪各种余额状态
在打款时计算佣金 收入确认跟随打款调度走 在赚取时点确认佣金
准备金被当作收入削减 模糊了时间和风险 分别追踪扣留、释放和核销
退款应用到最近一次打款 破坏了订单归属关系 将退款关联到原始交易
修改已过账的分录 破坏审计追踪线索 冲销并重新过账
重复触发 Webhook 重复贷记和打款 幂等键、重复检测
仅按金额和日期匹配 不同的项目相互碰撞冲突 按打款 ID、交易 ID、卖家、币种匹配

我会优先做什么

在触碰会计科目表之前,先画出资金流向图。写下从扣款到准备金释放的每一个事件,并标明哪些事件产生收入、哪些产生负债、哪些仅仅移动状态。

接着,构建一个端到端的完整流程并证明其平衡性:正常销售、部分退款、打款后拒付、准备金的扣留与释放,以及打款失败。使用已知的预期余额运行这些流程。如果应付卖家款项控制账户等于子分类账的总和、处理商清算账户与结算报告相符、银行存款与打款 ID 相符,那么你就拥有了一个能运转的核心骨架。

只有在第一个月顺利结账且暂记账户余额为零之后,才能开启期间锁定功能。过早锁定只会把错误冻结在账里。

Nordlet 开箱即用地沿用这些准则来过账结算:平台的佣金计入佣金收入,卖家的份额计入应付卖家款项,处理商手续费计入支付处理费,任何尚未归属的金额计入暂记账户。分类账期间将一直保持开放,直到你显式将其锁定,因此只要暂记账户清零,第一个月就可以结账。功能页面列出了包含的具体特性。

FAQ

买家的付款在任何情况下都是平台的收入吗?

仅针对平台作为主要责任人的特定商品或服务。对于代理人多边市场销售的卖家商品,收入是佣金,卖家的份额是负债。在同一个订单中,平台既可以充当履约服务的代理人,又可以充当底层商品的主要责任人,因此评估标准是针对特定的商品或服务,而不是针对整家公司。

准备金应该冲减收入吗?

不应该。准备金是时间和风险的分配,而不是收入调整。当你扣留资金时,应将资金从应付卖家款项转入准备金负债,释放时做相反冲销。卖家的资金目前是否被扣留为准备金,完全不影响收入和佣金的确认。

如何防止 Webhook 重试导致的重复打款?

为每个外部事件附加一个幂等键,例如将打款批次设为 processor:payout_id,并在写入时检测重复事件。提供商明确警告过可能会重复投递 Webhook,因此分类账必须拒绝第二次尝试,而不是再次过账。

卖家余额可以为负吗?

可以,模型必须允许这种情形。在卖家已经获得打款之后才落地的拒付,会导致平台面临来自卖家的应收款或者自己承担损失。压制负余额只会隐藏未记录的债务。

为什么要按打款逐笔对账,而不是按月汇总对账?

因为当汇总一个月的数据时,时间和差错会相互抵消,导致总账能够对平,但个别交易却是错误的。按打款批次进行对账,根据打款和交易 ID 进行匹配,能够在结账前浮现出缺失的事件、重复项以及归属错误的拒付。

延伸阅读