期末结账

锁定并关闭会计期间:结账清单、锁定期间会阻止什么,以及如何重新打开。

是按过账日期分配交易的日历月。会阻止进一步过账,并为报表快照其余额。Carbon 使用三态生命周期,并要求结账清单通过后才能关闭。

只有公司设置会计后才能使用期末结账。在此之前,日记账是暂记:它们没有期间,Carbon 不会为其创建期间,锁定或关闭期间会被拒绝,错误为 "Set up accounting before you post journals, runs or period closes." 设置会计会关闭所有在切换日期之前结束的期间。

结账生命周期

期间的结账状态(periodCloseStatus)沿单一方向推进,除非显式重新打开。它与旧的 Active/Inactive 标志无关,后者用于标记当前期间以进行惰性自动创建。

偏轨状态
已锁定
拒绝业务过账;会计调整仍可过账。这是你在最终确定前复核的暂存状态。

期间必须先锁定才能关闭——关闭打开的期间会被拒绝,错误为 "Period must be locked before closing."。状态转换在 accounting.service.ts 中(lockAccountingPeriod、unlockAccountingPeriod、closeAccountingPeriod、reopenAccountingPeriod),每项都会拒绝从错误起始状态发起的操作。

NOTE

对某一类操作,锁定比关闭更严格

已锁定期间仍接受会计调整——以会计调整意图过账的手工日记账可以通过。它只阻止业务单据。已关闭期间阻止一切,包括冲销进入。当本月业务已结束但会计尚未完成时锁定;当账务最终确定时关闭。

锁定或关闭期间会阻止什么

关卡位于 getOrCreateAccountingPeriod,每个过账路径在写入前都会调用:

字段类型
任何过账都会被拒绝,错误为 "Accounting period is closed. Reopen it before posting."——业务单据和调整都一样。
业务单据被拒绝,错误为 "Accounting period is locked. Post as an accounting adjustment or unlock the period first." 会计调整可以通过。
一切正常过账。

数据库触发器(check_accounting_period_open)是服务层检查之下的硬性兜底:它拒绝任何日记账的 INSERT、DELETE 或期间移动进入或离开已关闭期间,因此即使是 service-role 任务或过账也无法把分录塞进已关闭月份。(锁定语义需要操作者身份,因此在服务层执行;触发器只守卫已关闭不变式。)触发器允许的唯一例外是 Posted → Reversed 状态翻转,因为抵销的冲销会落在打开期间。Draft → Posted 或 Provisional → Posted 变更属于过账,因此触发器按插入检查。

结账清单

关闭通过一份持久化的清单执行——公司级的任务定义模板(periodCloseTaskDefinition),加上首次打开某期间结账界面时物化的按期间实例(periodCloseTask)。每家公司预置九个系统任务(可以停用但永不删除)。每个任务有类型(Auto、Action 或 Manual),Auto 任务带严重程度。

字段类型
由系统实时运行的就绪评估器——检查通过时任务显示 Done,失败时显示 Open。你不勾选它们;它们反映真实状态。
完成就是一次生命周期转换的任务。「Lock the period(锁定期间)」是 Action 任务:其按钮驱动 Open→Locked 翻转,Done 状态来自期间的结账状态,而不是存储的勾选。
由人工签核(例如「Review financial statements(复核财务报表)」),你自己标记完成。

Auto 任务失败时关闭(fail closed):找不到评估器的 Auto 任务被视为失败,而不是静默通过,因此结账保持受控,原因保持可见。

严重程度把关不同

Auto 任务的严重程度(periodCloseTaskSeverity)决定失败的检查是阻止结账还是仅警告:

字段类型
失败的阻止检查会硬性停止结账。在它通过之前无法关闭期间(或跳过任务,而阻止项不允许跳过)。
失败的警告检查会显示问题,但不阻止结账。可以继续,或带原因跳过任务。

预置检查来自 computePeriodReadiness:

检查严重程度失败条件
过账待处理的业务单据阻止存在日期在本期间的未过账收货/发货/发票。
过账或改期草稿日记账分录阻止存在日期在本期间的草稿日记账分录。
本期间试算平衡阻止任一已过账日记账借贷不等。
过账覆盖本期间的折旧运行警告有草稿折旧运行在本期间结束。
匹配并抵销公司间交易警告存在涉及本公司的未匹配公司间交易。

第七个预置 Auto 任务 Review negative on-hand inventory(复核负现有库存)(警告)尚无实时评估器,因此它会失败关闭,作为一个持续警告存在,需带原因跳过。其余三个预置任务是两个 Action 步骤(Lock the period、Close the period)和一个 Manual 步骤(Review financial statements)。

完成任务与跳过任务

Action/Manual 任务通过 completeTask 标记完成(可选备注)。任何非阻止任务都可以用 skipTask 跳过,后者始终要求非空原因——并且服务额外拒绝跳过阻止任务。Auto 任务从不手动完成;其状态在每次加载清单时从实时就绪检查推导。

结账本身(closePeriodWithChecklist)会在服务端重新评估整个清单。除非所有必需任务都解析为 Done 或 Skipped 且没有失败的阻止检查,否则拒绝关闭,并在错误中指明具体的阻塞任务。永远不要相信被禁用的按钮:关卡在服务端执行,数据库触发器是最后兜底。

HEADS UP

顺序关闭与重新打开

期间按顺序关闭和重新打开。如果任何更早期间未关闭,关闭会被拒绝("Earlier periods must be closed first")。如果任何更晚期间仍为已关闭,重新打开会被拒绝("Later periods must be reopened first")——从最近的结账向前回溯重新打开。

重新打开

重新打开(reopenAccountingPeriod)把已关闭期间翻回打开,清除其 closedAt/closedBy,并删除结账写入的余额快照(它自己的以及任何嵌入了它的更晚快照,因为快照是截至其期末日期的累计值)。重新打开后,进入该月的过账恢复,余额读取回退到全历史扫描,直到期间再次关闭。未关闭的期间不能重新打开。

解锁(unlockAccountingPeriod)是更温和的反向操作:把已锁定移回打开,使业务单据可以再次过账,并清除 lockedAt/lockedBy。它不写快照,也不触碰余额。

会计期间与日历

期间按财年生成——从公司财年起始月开始的十二个月度期间,通过 createFiscalYearPeriods(幂等;跳过已存在的期间编号)。每个期间带有从该起始月推导的 fiscalYear 和 periodNumber:财年以其结束的日历年命名,因此 2025 年开始的 7 月制财年是 FY2026。

一旦日历已提交——存在任何过账,或任何期间已锁定/关闭——财年起始月即锁定(getFiscalCalendarCommitted),因为重新标注已报告期间会改写历史。空的、打开的期间仍可删除(deleteAccountingPeriod)并重新生成;已过账日记账或处于任何非打开状态的期间则不能。

会计档案

已结账的期间可以在会计 → 结账 → 会计档案归档。一份档案记录:期间、期间内的每张凭证、该清单的哈希,以及资料可以销毁的日期——期间结束后的 30 年,即《会计档案管理办法》给凭证与账簿的保管期限。

  • 归档范围。 已过账与已冲销的记账凭证、非草稿的销售与采购发票、已过账的付款、备忘、收货与发货——每次归档都是同一集合、同一顺序,所以哈希稳定。没有凭证的已结账期间也可以归档,集合为空。
  • 校验。 校验档案会用今天的账簿重建该集合,与存档哈希比对。“档案与账簿一致”表示期间结账后没有新增、删除或改期任何单据;否则会列出缺失与新增的单据。
  • 删除。 只有期间重开之后才能删除——已结账期间的档案就是结账记录本身,重开后再归档一次即可。
  • 一期一档。 重复归档会被拒绝。

相关内容