Why your order system and your payment provider disagree

Why your order system and your payment provider disagree

为什么你的订单系统与支付服务商的数据对不上?

Twice a month somebody in operations finds a number that doesn’t match. An order recorded at €120.00 against a capture of €119.40. Or an order with no payment at all. Or, the one that ruins the afternoon, a refund larger than anything that was ever collected. Then a week goes by. Operations says the payment system is wrong, engineering says the order system is wrong, somebody exports both into a spreadsheet, and the spreadsheet becomes the thing everyone argues about instead of the systems. A decision gets made in the end because the week ran out, not because anyone worked out what happened.

每个月总有那么两次,运营人员会发现账目对不上。比如订单记录显示 120 欧元,但实际扣款只有 119.40 欧元;或者订单完全没有支付记录;又或者最让人头疼的情况——退款金额竟然超过了收款总额。接着,一周的时间就这么过去了。运营部门说是支付系统出了错,工程部门说是订单系统有问题,于是有人把两边的数据导出到电子表格里,结果大家争论的焦点从系统本身变成了表格。最终做出决定往往是因为时间耗尽了,而不是因为有人真正搞清楚了问题所在。

I’ve watched this in banking, in healthcare, in gaming and in public administration. Every team was sure their situation was unusual. It never was. There are four ways this goes wrong, they look the same from a distance, and each one needs a different answer. That’s why the week disappears.

我在银行业、医疗保健、游戏行业和公共管理部门都见过这种情况。每个团队都坚信自己的情况很特殊,但事实并非如此。导致账目不符的原因通常只有四种,从远处看它们长得一模一样,但每一种都需要不同的解决方案。这就是为什么解决问题会耗费整整一周。

The basket changed and nobody wrote it down

购物车变动了,但没人记录下来

A customer starts a checkout at €120, adds something, pays €150. Your order system has both numbers in it somewhere. Your provider only ever saw one. Pull the two exports on different days and they’re €30 apart, and neither of them is lying. This is the common one, and there’s nothing broken: the records describe two versions of the same purchase, and nothing in the export tells you which version you’re holding. You’ll spot it because the same order identifier carries two totals, or because a total moved between one export and the next. There’s nothing to do to the money — fix the export so each version of a basket carries its own identifier, and the disagreement stops existing.

客户开始结账时金额为 120 欧元,随后添加了商品,最终支付了 150 欧元。你的订单系统里存着这两个数字,但支付服务商只看到了其中一个。如果在不同时间导出两份数据,你会发现它们相差 30 欧元,但双方都没有撒谎。这是最常见的情况,系统并没有坏:这些记录描述的是同一笔购买的两个版本,而导出文件中没有任何信息告诉你当前持有的是哪个版本。你可以通过同一个订单号对应两个总额,或者总额在两次导出之间发生了变动来识别它。这不需要处理资金问题——只需修改导出逻辑,让每个版本的购物车拥有独立的标识符,分歧就会消失。

One payment, taken in two goes

一笔支付,分两次完成

A €150 order captured as €100 and then €50. A partial capture, a retry after a decline, two cards. Look at the totals and it reads as €50 missing; look at the transactions one by one and it reads as a payment nobody asked for. Both readings are wrong, and both are what you get from a spreadsheet left to itself. The giveaway is that the captures add up to the order total. Again there’s nothing to do to the money, but notice that any comparison working on totals will flag this every single time. That’s how teams learn to stop reading the report.

一笔 150 欧元的订单被拆分为 100 欧元和 50 欧元两次扣款。这可能是部分扣款、支付失败后的重试,或是使用了两张卡。看总额,会觉得少了 50 欧元;逐笔查看交易,又会觉得多出了一笔没人要求的支付。这两种解读都是错的,而这正是电子表格自动处理的结果。关键线索在于,这些扣款加起来正好等于订单总额。同样,这不需要处理资金,但请注意,任何基于总额的对比工具每次都会将其标记为异常。这就是为什么团队最终不再信任这些报告。

The same payment counted twice

同一笔支付被计算了两次

Your provider reports a capture, your ledger reports the same capture, and if you add them the order looks overpaid by exactly its own value — so somebody starts preparing a refund. This one is dangerous because it doesn’t look like a duplicate, it looks like a finding. It hands you a plausible number and a plausible thing to do about it, and the thing to do is wrong. You’ll see two records pointing at the same operation identifier from two different sources. The fix isn’t technical: decide once which source is authoritative for each kind of record, and write it down somewhere people can find it. No comparison can work this out on its own, because there’s no fact in the data that says which system to believe.

支付服务商报告了一笔扣款,你的账本也记录了同一笔扣款,如果将两者相加,订单看起来就像是多付了整整一倍的金额——于是有人开始准备退款。这种情况很危险,因为它看起来不像重复记录,而像是一个“发现”。它给了你一个看似合理的数字和看似合理的处理方案,但这个方案是错的。你会看到两条来自不同来源、指向同一个操作标识符的记录。解决方法不是技术性的:确定哪种记录以哪个来源为准,并将其记录在大家都能找到的地方。没有任何对比工具能自动解决这个问题,因为数据中没有任何事实能说明该相信哪个系统。

A record that never turned up

记录从未出现

A webhook that failed and never got retried. A nightly export that ran while a transaction was still in flight. A refund somebody in support issued from the provider’s dashboard, which your order system never heard about. This is the only one of the four that’s a real problem, and it’s the one that looks most like the other three. The difference is that the record isn’t different, it’s absent. Before anything else, find out why. A missing record isn’t a discrepancy to reconcile, it’s a hole in how two systems talk to each other.

Webhook 失败且从未重试;夜间导出任务在交易进行时运行;客服人员在服务商后台操作了退款,而你的订单系统对此一无所知。这是四种情况中唯一真正的问题,也是最容易被误认为是前三种情况的问题。区别在于,记录不是“不一致”,而是“缺失”。在做任何事之前,先找出原因。缺失的记录不是需要核对的差异,而是两个系统通信机制中的漏洞。

Why the week disappears

为什么会耗费一周时间

Three of those four aren’t errors. The records are incomplete, or duplicated, or describing different moments, and not one of them is fixed by adjusting a figure. So the team spends the week arguing about which system is wrong, when the question was which of the four they were looking at. That question takes minutes if the comparison is built to tell them apart, and it’s unanswerable in a spreadsheet, because a spreadsheet compares totals and all four produce a total that doesn’t match.

这四种情况中有三种并非错误。记录要么是不完整的,要么是重复的,要么描述的是不同的时间点,没有哪一种可以通过调整数字来修复。因此,团队花了一周时间争论哪个系统出了错,而真正的问题应该是他们面对的是这四种情况中的哪一种。如果对比工具能区分这些情况,这个问题几分钟就能解决;但在电子表格中,这是无法回答的,因为电子表格只会比较总额,而这四种情况都会导致总额不匹配。

What a comparison has to do before it’s worth anything

有价值的对比工具必须具备什么?

It has to refuse to guess. Two versions of a basket and no rule for choosing between them: say so, don’t pick the bigger one. The same payment from two sources: say two systems are claiming this, don’t add them up. A record that isn’t there: say it isn’t there, don’t treat it as a zero. And when it does say everything agrees, that has to mean something narrow and stated out loud — the records you gave it are consistent with each other. Not that the money arrived. Not that your provider’s history is complete. The moment a green result means more than the evidence behind it, somebody has to check it by hand, and you’re back where you started.

它必须拒绝猜测。面对两个版本的购物车且没有选择规则时:直接指出来,不要自作主张选大的那个。面对来自两个来源的同一笔支付:指出两个系统都在认领它,不要把它们加在一起。面对缺失的记录:指出它不存在,不要把它当作零。当它显示“一切一致”时,其含义必须是狭义且明确的——即你提供给它的记录彼此一致。这并不代表钱已经到账,也不代表服务商的历史记录是完整的。一旦“结果通过”的含义超出了其背后的证据,就必须有人进行人工核对,你又回到了原点。

The last one is the one everybody skips. You have to be able to reproduce the answer without the thing that produced it. If I tell you order 4,412 is €40 short, you should be able to take the same inputs, run the comparison yourself, and either get my number or prove me wrong. A finding you can’t check is a finding you have to trust — and trust is exactly what nobody had during the week they spent arguing.

最后一点是每个人都会忽略的:你必须能够在没有原始工具的情况下复现结果。如果我告诉你订单 4,412 少了 40 欧元,你应该能够使用相同的输入,自己运行对比,要么得出和我一样的数字,要么证明我错了。一个无法验证的结论只能靠“信任”——而这正是大家在争论的那一周里最缺乏的东西。

I build software that does this and I take engagements on it. You send anonymised order, capture and refund records; you get the findings back with evidence your engineers can recompute on their own machines. trustedpai.com

我开发了专门处理此类问题的软件,并提供相关咨询服务。你可以发送匿名化的订单、扣款和退款记录,我将返回带有证据的分析结果,你的工程师可以在他们自己的机器上重新计算并验证。trustedpai.com