复核流程

一家公司如何从一个存放工作簿的文件夹,走到一个已结账、已锁定的月份:公司提交什么,哪些事项只需您决定一次,以及此后每个月会发生什么。

什么是复核

一次复核就是一次结账:针对一家公司、一个月份运行一次流程。Haruno 读取该公司的工作簿,据此构建一本标准化账簿,运行完整性检查,并生成报表包、对账底稿和仪表板。随后,它会锁定本次报出的月份,这样已报出的数字日后就不能在不留记录的情况下更改。

公司与 client
Haruno 将每家公司称为 client(客户);文件夹名称、命令和仪表板中用的都是这个词。

目前,复核在 macOS 应用中运行。仪表板和任何一份报告都可以导出为 PDF。

结账的各个阶段

阶段读取写入
读取workbooks/<client>/ 中的每个工作簿或 CSV 文件从每个文件读出的表格,存放在 ledger/staging/ 中。隐藏工作表会被搁置一旁,不予读取。
构建账簿上述表格,以及该公司已批准的映射配置(spec)标准化账簿 ledger/ledger.sqlite
检查账簿发现事项和待确认事项,列在结账报告中
报表账簿,以及映射配置中的报表结构报表包
对账账簿中的对账明细表对账底稿
锁定本次结账报出的月份,以及未解决的发现事项每个月一条结账记录:“fully reconciled”(已全部核对一致)或“reported with exception”(附例外事项报出)
仪表板账簿;在本次运行中的所有公司都完成结账后读取一次,涵盖每一家有映射配置的公司投资组合仪表板

检查在生成任何报告之前运行,也是整个流程的核心。发现事项不会中止结账:它指出的,正是您原本要到第三周才会发现的情况。

同一次运行还会生成投资者报告和调整记录,并为每个源工作簿保留一份副本。详见“结账会生成哪些文件”。

公司需要提交什么

公司提交的,是其记账人员本来就会编制的资料。有财务资料包和对账底稿,就足以完成一个月的结账;普通的 QuickBooks 报表导出文件也可以代替财务资料包。其他输入都是可选的,每多提交一项,就多一个面板或一项检查。

输入用于
月度财务资料包:在同一个工作簿中包含粘贴进来的导出数据、手工填写的映射列和各列报工作表账簿和报表包。科目映射和小计从工作簿自身的公式中读取。
QuickBooks 报表导出文件:资产负债表、利润表、现金流量表同上,科目映射根据每份导出文件的分节推断。三份都要提交:现金流量表会按其自身声明的分类保留下来,这样检查才能指出与之不一致之处。
试算平衡表(可选)一项检查:确认每个有余额的会计科目都已在报表中列报。单独提交试算平衡表会被拒绝,因为它本身不列报任何内容。
对账底稿对账底稿及其相关检查。每张明细表都会按其自身明细重新加总,并与总账核对。
预算(可选)预算与实际对比面板。差异不等于发现事项。
经营数据工作表(可选):按月列示的员工人数和新增客户数员工人数、人均运营费用和人均收入指标卡,以及新增客户数;任何报表都不包含这些数量
账单导出文件,例如 Stripe 发票(CSV)(可选)按客户列示的收入,以及 MRR、ARR 和流失率
CRM 导出文件,例如 HubSpot 交易(CSV)(可选)签约额(bookings)和新增客户数,它们都不是收入
按客户列示收入的电子表格(可选)同样的 MRR、ARR 和流失率,但按已确认的收入读取,而不是按已开具的发票读取
“Profit and Loss by Class”(按类别列示的利润表)导出文件,每月一个文件(可选)按部门列示的运营费用面板,以及一项检查:每个月按类别拆分的金额加总应等于该月的发生额(class_total_disagrees)。没有文件的月份显示为短横线,而不是零。
“A/R Aging Detail”(应收账款账龄明细)和“Transaction List by Vendor”(按供应商列示的交易清单)(可选的 QuickBooks 报表)可据以判定某月的金额骤增是否属于预付款的发票;在您指定应收账款科目后,还会将未结清发票与应收账款余额进行核对

导出文件须满足的要求

  • 按权责发生制编制。收付实现制的导出文件会被拒绝。
  • 按月列示。按季度分列的利润表会被明确拒绝;请索取按月列示的报表。
  • 使用该公司的报告货币。每家公司只有一种货币,不做任何换算,因此声明为其他货币的导出文件会被拒绝。
  • 由映射配置认领。映射配置中没有任何部分提到的文件,会被列出文件名并跳过,该公司的其余资料仍照常完成结账。

隐藏工作表被隔离,不予读取

隐藏工作表只记录名称,从不导入;在实务中,隐藏工作表常常存有其他公司遗留下来的数据。只有在您要求时,Haruno 才会向您展示其中的内容;也只有在您确认它属于某家公司之后,才会将其纳入该公司的账簿。详见“隐藏工作表会被搁置一旁”。

接入一家公司

没有映射配置的公司无法结账。接入流程会生成这份映射配置,而且只需进行一次。

  1. 在 macOS 应用中通过“File ▸ Open Folder…”(文件 ▸ 打开文件夹,快捷键 ⌘O)打开复核工作区:也就是包含 .haruno 的那个文件夹,而不是它的上一级文件夹。
  2. 将该公司的工作簿放入 workbooks/<client>/,例如 workbooks/acme/:包括月度财务资料包、对账底稿,以及预算(如有)。
  3. 让 Haruno 为该公司完成设置。
    text
    Acme 刚签约,他们的文件在 workbooks 里,帮他们完成初始设置。
  4. Haruno 根据工作簿起草一份映射配置,然后暂停并展示给您,最先展示的是 REVIEW 清单:即仅凭工作簿无法确定的事项。此时尚未应用任何内容。
  5. 阅读 REVIEW 清单,并用日常语言逐项回答。Haruno 会记录每条回答,并向您展示修改对比(diff)。
  6. 批准后,结账随即运行。
对话会发送什么
通过助手完成接入时,您输入的内容以及工具输出的内容(例如科目名称、说明文字和数字)会经 Inferara 的托管服务发送给作答的模型提供方。结账本身在您的电脑上运行。如果不想让客户数据进入对话,请自行运行这些命令:参见下文“自行运行”一节。

对于财务资料包,草稿并非猜测:报表本身写明了它的计算关系,因此每条科目映射都读自把某个科目归入某一报表项目的 SUMIF 公式,每个小计都读自其上方的 SUM 公式。普通的 QuickBooks 报表导出文件不带科目映射。对于这类文件,草稿会根据每份导出文件的分节推断科目映射,而把 QuickBooks 的项目名称改成您向投资者列报时使用的名称,是 REVIEW 清单中的主要事项。

什么是映射配置

映射配置是每家公司一份的 YAML 文件,位于 .haruno/skills/QuickBooksCFO/specs/<client>.yaml。它完整记录了该公司的账目如何映射到报表:哪些会计科目汇入哪个报表项目、每个小计由哪些项目构成、哪些项目与正常余额方向相反列示,以及公司名称、金额单位、报告货币、重要性水平,还有您一经说明便会记入的会计政策。它是纯文本,便于人工阅读;凭一份映射配置和一个工作簿,就能复现一次结账。

REVIEW 清单

工作簿无法说明的,是判断。这些事项会以一份标题为 # REVIEW: 的清单形式出现在草稿顶部。请认真阅读:这就是科目映射对话,每家公司只进行一次。典型事项包括:

  • 重要性水平,即多大金额算重要:以美元计,而不是报表列报所用的千元单位;
  • 哪些缺失的对账属于预期情况:清单会列出对账底稿中没有明细表的会计科目,供您从中确认;
  • 资本化政策:资本化门槛、折旧方法、使用寿命;
  • 哪些报表项目预期为空,以及会计科目编号如何对应分类;
  • 需要确认的读取结果:从封面页读出的公司名称、金额单位,以及资产负债表底部一行未加标签、被识别为 CHECK 行的数据,即本应为零的勾稽核对行。

认可某项读取结果不会写入任何内容;更正才会被写入。请核对金额单位:如果把过时的 ('000) 标注误当作正确而予以接受,所有交付文件中的每个数字都会相差一千倍。回答用日常语言即可:

text
重要性水平是 $1,000,现金在 QuickBooks 里对账。

Haruno 会记录这两条回答并展示修改对比。“现金在 QuickBooks 里对账”是一项豁免:即对缺失对账检查认可的例外,而不是科目映射。该公司一旦有了已结账的月份,Haruno 会列出这项豁免涵盖哪些会计科目;首次结账之前,没有可供匹配的对象。不涵盖任何科目的豁免,会在下一次结账时报告为 unused_exemption

首次结账前回答清单中的全部事项
清单只回答一半就结账,真正的发现事项会淹没在一堆针对其他科目的发现事项里,而对账底稿本来就不会为那些科目编制明细表。

哪些事项绝不替您决定

有些数字是对一家企业的书面判断,只有公司自己能给出。如果草稿写入了账目中没有载明的值,例如重要性水平、年限平均法(直线法),或在导出文件未声明货币时写入的 USD,请把它当作有待确认或更正的默认值。Haruno 从不记录您未曾说明的资本化门槛或使用寿命。它会以您说明的内容为准核对公司的明细表,而且助手绝不会代您回答这些事项。

政策Haruno 的处理方式
重要性水平草稿中带有一个明示的默认值,并在 REVIEW 清单中标注为有待更正的数字,而不是读取得到的数字。
资本化门槛不起草。在您写明门槛之前,不会对照门槛报告任何内容。
使用寿命不起草。固定资产登记簿中的使用寿命是该明细表自己的选择;把它们照搬为政策,等于用明细表检验它自己。
折旧方法年限平均法是唯一会计算的方法,因此草稿会写入它并加以标注。其他方法会被拒绝,而不是用错误的算法去检查。
货币从导出文件声明的货币读取;未声明时为 USD;从不换算。

即使未说明任何政策,schedule_drift 仍会运行其中无需判断的那一半:将固定资产登记簿所隐含的明细表与总账进行核对。另有三项判断同样由您作出:某月的金额骤增是否属于预付款,某项余额是否在别处对账,以及重新开启已锁定月份的原因。

科目映射对话

新的会计科目会出现,科目映射也会逐渐偏离。对于没有任何报表项目认领的会计科目,如果它有余额,结账会将其报告为 unmapped_active_account(高);如果它迄今一直为零,则报告为 unmapped_empty_account(低)。此后的流程始终相同:Haruno 提出建议,由您确认。

  1. Haruno 会对照勾稽核对结果解读这项发现事项。如果 CHECK 行的差额恰好等于该科目的余额,原因就是这个未映射科目,一条科目映射即可同时消除未映射科目的发现事项和勾稽核对的发现事项。
  2. 它会根据该科目的名称、编号区间和相邻科目提出一个报表项目,并附上理由。
  3. 您确认后,它会记录这条科目映射,并为该公司重新结账。如果该公司之前已结过账,这次结账会被拒绝,直到您给出原因:参见下文“结账被拒绝时”一节。

改变主意

text
1450 Deposits Receivable 应归入 Other assets。

Haruno 会以可供复核的 YAML 形式提出这项更改,而不是直接修改您的电子表格:

yaml
mappings:
  "1450": "Other assets"

即使重新导入的工作簿中,其自身的映射列仍为空或仍有错误,已批准的科目映射依然有效。Haruno 会报告两者的不一致,而不会改回文件中的映射,也绝不会删除您批准过的科目映射。

豁免不等于科目映射

一项豁免只了结一个疑问:这项余额在哪里对账,这个项目为什么为空,或者这次骤增是否属于预付款。对账豁免不会把该科目放进任何报表,因此它所带的余额在所有报表中依然缺失,unmapped_active_account 仍会报告它。此外,与总账核对不符的明细表,任何科目映射都无法修正;这项例外是真实存在的。

回答通过命令记录,而非手工编辑
Haruno 用其 answer 命令(ingest.py answer,见“自行运行”一节)记录 REVIEW 回答和科目映射变更,从不手工编辑映射配置。手工编辑会破坏 REVIEW 清单及其注释,可能导致映射配置无法再加载,并使已批准的判断无从追溯。如果某条回答所需的值没有对应的 answer 参数,Haruno 会如实说明,并请您亲自完成这一处编辑。

月度结账

完成接入后,每个月运行的都是同一套流程,无需再进行科目映射对话。

  1. 将当月的工作簿添加到 workbooks/<client>/。
  2. 让 Haruno 对该月结账。
    text
    帮 Acme 做本月结账,新的工作簿已经放进来了。
  3. Haruno 用一条命令完成结账:读取工作簿、应用已批准的映射配置、运行检查、生成报表包和对账底稿、锁定相关月份并刷新仪表板。
  4. 在任何文件对外分发之前,它会先向您说明发现事项。无论有无发现事项,报表包和对账底稿都会生成;发现事项告诉您在它们发出之前需要处理什么。

结账报告

结账会为每家公司输出一份报告:

说明的内容
第一行公司名称、是否已完成结账、读取的工作簿,以及发现事项和待确认事项的数量
read but not applied映射配置中没有任何部分认领的每个文件,逐一列出文件名
RESTATED 及其他提示重新提交的工作簿带来的重述数字,以及文件与映射配置不一致的科目映射
[high], [medium], [low]每行一项发现事项:严重程度、检查项、对象和详情
?每行一项待确认事项,例如 prepaid_candidate:只向您提出,从不计为发现事项
re-opened根据您给出的原因重新开启的月份
locked已锁定的月份和结账状态,并列出未解决的检查项名称
restated有多少个数字发生变动;每个变动的数字在调整记录中占一行
wrote生成的每个文件:报表、对账底稿、投资者报告、调整记录、仪表板

锁定行的样式如下(合成演示数据):

text
locked 2023-02-28 … 2026-06-30 (41 periods) — reported with exception: 3 unresolved finding(s) (presentation_tieout, recon_exceptions, unmapped_active_account); re-opening one needs a reason (`ingest.py reopen`)

有发现事项的结账同样是成功的结账。“clean”表示没有严重程度为高或中的发现事项。详见“严重程度”。

结账被拒绝时

一个月份一经报出即被锁定。如果某次导入会更改、删除或新增已锁定月份中的数字,该公司的结账就会中止:不会向其账簿写入任何内容,也不会刷新它的任何报告。同一次运行中结账的其他公司照常进行。这类导入包括已批准的科目映射,或对某个报表项目加总方式的更改(即使工作簿中没有任何数字变化,二者也都会使报表发生变动),以及针对已锁定月份的更正导出文件。拒绝信息会列出将发生变动的月份和数字,并给出前后两个值:前十二项完整列出,其余只给出数量。它还会输出可以重新开启这些月份的命令。如果导入的数字与原来相同,则不会有任何提示,因此重新运行一次内容未变的结账不受影响。

text
2023-02-28 … 2026-06-30 are CLOSED, and this import would change what have
been reported for them. Nothing was written.

  2023-02-28  presentation  BS line 'CHECK': -6,600.00 -> 0.00
  2023-02-28  presentation  BS line 'Other assets': 19,500.00 -> 26,100.00
  2023-02-28  presentation  BS line 'TOTAL ASSETS': 5,394,868.29 -> 5,401,468.29

以上摘自一次基于合成数据的演示结账,该结账发生在为一家已锁定 41 个月的公司批准上文的 1450 科目映射之后。

给出原因

Haruno 会转告拒绝信息,然后停下。它不会自行重新开启月份,也不会替您撰写原因:原因会永久保存在因它而得以变动的数字旁边,因此必须是您自己的话。如需继续,请说明原因:

text
1450 此前未映射;已批准归入 Other assets。

这样会恰好重新开启拒绝信息中列出的那些月份,为每个月份记录该原因,并重新完成结账。占位文字(例如拒绝信息中用方括号给出的示例)会被拒绝。不给出原因,就什么都不会改变。如果有数字发生变动,此后的每一份报表包都会附带“Restated periods”(重述期间)表,每个变动的数字都会在调整记录中占一行。详见“锁定”。

勾稽不符的月份同样会被锁定

报表勾稽不符的月份不会被拒绝。它会像其他已报出的月份一样被锁定,锁定记录会将其标为“reported with exception”并列出未解决的检查项名称,而不是标为“fully reconciled”。锁定不等于对账目下了定论。详见“结账状态”。

其他拒绝是在向您提问

对于不靠猜测就无法读取的输入,结账也会拒绝并说明原因,例如目录页上出现两个不同月份日期的对账底稿。Haruno 会向您询问,并将回答记录在映射配置中。它绝不会为了让错误消失而修改公司的工作簿。

多家公司

一个工作区可以容纳您复核的所有公司:每家公司在 workbooks/ 下有一个文件夹和一份映射配置,投资组合仪表板则覆盖全部公司。如需一次接入多家公司:

text
这些是我客户的电子表格。导入 workbooks/ 中的全部内容——每个文件夹一个客户。对每个客户:读取其工作簿,提出科目映射建议,并在应用任何内容之前先给我看 REVIEW 说明,然后完成本月结账并刷新仪表板。
  • 所有映射配置会先全部起草,再一并展示给您。各份草稿共有的 REVIEW 事项只询问一次。
  • 共用的回答会写入每一份映射配置;针对某一家公司的例外只适用于该公司。
  • 所有公司在同一次运行中各自独立结账,因此某个工作簿格式有误,只会导致其所属公司的结账失败。
  • 仪表板在最后统一刷新一次。只对一家公司结账,也会刷新整个投资组合。
  • 在仪表板上,每家公司只对应一份映射配置:如果两份映射配置指向同一家公司,仪表板只根据其中一份构建,结账会说明保留了哪个文件、原因是什么,以及排除了哪个文件。

公司之间不做任何换算,投资组合合计也不会把以不同货币报告的公司加总在一起。详见“投资组合视图”。

自行运行

这套流程是您工作区中的普通 Python 脚本,归您所有。在工作区文件夹中运行:

bash
# 读取工作簿,但不导入
python3 .haruno/skills/QuickBooksCFO/scripts/ingest.py inspect "workbooks/acme/financial-package.xlsx"

# 根据该公司自己的工作簿起草映射配置,然后阅读 REVIEW 部分
python3 .haruno/skills/QuickBooksCFO/scripts/ingest.py propose-spec "workbooks/acme/financial-package.xlsx" --spec-name acme --out .haruno/skills/QuickBooksCFO/specs/acme.yaml

# 用 answer 命令回答 REVIEW 事项,不要直接编辑文件
python3 .haruno/skills/QuickBooksCFO/scripts/ingest.py answer --spec .haruno/skills/QuickBooksCFO/specs/acme.yaml --materiality 1000

# 结账:暂存、账簿、检查、报表、对账底稿、仪表板
python3 .haruno/skills/QuickBooksCFO/scripts/close.py --workspace . --client acme

它只需要标准的 Python 3,别无其他:无需安装任何东西,无需账户,也无需联网。它读取和写入的所有内容都保留在工作区文件夹中。请给每个文件路径加上引号,因为实际的导出文件名常含空格和括号。如果结账因锁定被拒绝而您需要继续,请在结账命令中加上 --reopen-reason 并附上您的原因;如需对所有公司结账,请用 --all 代替 --client

为何可能需要自行运行:结账本身在您的电脑上运行,无论是否使用助手,都不会传输任何客户数据。对话发送的,就是您发送的内容:您输入的内容和工具输出的内容(科目名称、说明文字、数字、发现事项)会经 Inferara 的托管服务发送给作答的模型提供方。在用它处理真实账目之前,请对照您自己客户的保密条款确认这一点。如果想保留这些便利,同时避开对话这一部分,请自行运行这些命令,只在不含客户数据的环节使用助手。详见“您的数据去向”。

后续步骤

深入了解结账会发现、展示和记录哪些内容。