常见的一幕:月报是周五发出去的,PDF、群消息、汇报材料用的都是同一个数。三天后,有人在商品表里把一个单价从 120 改成 138,改的人很谨慎,只改了这一行。第二天财务把上个月的报表调出来核对,销售额比发出去的那一版多了六万多。去翻那几张订单的变更历史,一条记录都没有——那几天没有任何人碰过它们。
没有人改过数据:这套表从一开始就没有把「当时是多少」存下来。背后是我们反复见到的四层机制,每一层单独看都合理,叠起来就是一张会自己变的报表。
四层叠在一起
第一层,查找引用不存值。 引用列显示的永远是对方表此刻的值,每次打开都是现算的。订单金额挂在商品表的单价上,「去年那一单卖了多少钱」这个问题,表其实一直答不出来,它只会回答「按今天的价,那一单值多少钱」。调一次价,等于把去年所有卖过它的订单都改写了一遍;变更历史却干干净净,因为这些订单本身没被动过,动的是另一张表里的一行,引用本来就没有「值被更新」这件事可记。
第二层,单选选项是共享对象。 记录里存的是那个选项本身,不是当时那串文字。为了统一说法把「差旅费」改成「差旅交通费」,前后不到三秒,三年前的单据现在显示的也是新名字;要是改成「业务招待费」,就是把三年的记录整批重新分类。同样没有任何一条记录被编辑过,同样在变更历史里翻不到。
第三层,没有「关账」。 按会计上的关账惯例,一个期间结完就不再往里记账,错了在本期调整,原来那笔不动。多维表格里一行记录从录进去那天起就一直能改,业务日期写着上个月,不代表它属于已经过去的上个月。仪表盘永远是活的,昨天发出去的数和今天点开的数,本来就不是同一个数。
第四层,归档等于口径永久分裂。 表卡了,把两年前的数据搬进归档表,数据一条没丢,可累计数从此少一块——这套表里没有「把两张表叠起来统计」这回事,凡是跨年的数都得靠人把两个数加起来,谁忘了加,报出去的就是个偏小的数,而且哪儿都看不出异常。
四层的共同点只有一个:报表上的数变了,报表自己不会说,也没有任何地方提示它变过。
主数据描述现在,交易记录当时
我们把判据收成一句话:这个数改了,去年的账要不要跟着变。 要,它是主数据的属性,引用着没问题;不要,它就必须在成交那一刻被抄进这一行,从此跟主数据脱钩。商品表、汇率表这类主数据天生就该变,变的只是表;去年那一单按哪个价、哪个汇率成交,是交易发生那一刻的事实,不是主数据现在的状态。把交易金额挂在主数据上,等于把已经发生的事实交给随时会变的现状去决定。
我们现在的规矩
- 单价、折扣率、汇率、税率、提成比例、成本价,这六样在成交那一刻固化成死值,金额只认固化后的值。固化是成对的:参与同一个毛利率计算的值要么全固化要么全不固化,只固化售价不固化成本,毛利率照样会变。
- 引用来的那一列可以留着,但改叫「当前售价」,只用来跟成交价比对,不进任何历史统计。
- 选项口径变了,只能新增一个、旧的停用,不能改名。真要合并历史,就显式地批量改记录,让每一条的变更历史里留下「从 A 改为 B」。
- 对外的数字只从快照表取,月报、历史趋势、汇报材料一律不引明细表的实时合计。快照里要存三个数:金额、条数、最后更新时间。条数变了是有人增删,条数没变金额变了是有人改了金额,看最后更新时间就知道是哪天动的。
- 补录是本期新增一条,不是回头改上月:业务日期写本期,金额写差额,备注写清调整的是哪个月、原单号。上月报出去的数永远对得上,差额从哪来翻一眼就知道。
- 业务日期和创建时间必须是两个字段。前者是「这件事发生在哪天」,后者是「谁什么时候录的」,按月统计只走前者。月底的单常常下月初才录,混成一个字段,每个月的形状都不对,年度合计却是对的,分月看才露馅。
- 关账日写进制度,快照在关账日之后跑。关账日不等于月末,补单补票总有几天滞后,月末当天跑到的是还没长完的数。
- 归档之前,先把跨年要看的累计数固化成历史汇总表,再搬明细。顺序反了,那两年就只剩一堆没人会想起去加的行。
- 验收时做一次三十秒自检:随便找一条去年的单记下金额,去商品表把对应单价改个数,回来看那单金额动没动,看完把单价改回去。动了,历史就全是活的。
图是活的,截图是死的。两拨人各拿一个版本开会,中间没有任何提示。
