





一层支付接口,通吃所有网关:Odoo POS 如何接入 WeChat Pay 与 Alipay
在中国做零售,支付从来不是选择题。顾客走到柜台,打开 App,扫码即付。真正值得琢磨的,是这一笔交易背后连着什么,以及你接入 Odoo 的方式,能不能扛住第三家门店、第二家支付服务商、下一次 Odoo 大版本升级。
多数第一次尝试,熬不到那时候。问题出在哪?一个能经得住折腾的方案,又该长什么样?
一次性方案,注定无法规模化
最常见的起步方式,是一段低代码工作流:拼好请求,调通接口,Demo 跑得漂亮。但让它慢慢烂掉的,往往不是支付业务本身,而是工程规范的缺失。商户密钥直接写死在流程里。运行环境自动更新,版本没锁定,一次你没做过的改动就能搞垮生产。顾客还在输密码的尬尴时刻,靠一堆分支节点硬撑,事后却查不到完整记录。重试和对账,很难做得可靠。每新增一个客户,就得手工重建整套流程,没有单元测试,也没有可复用的状态。
这些都不是支付的问题。这是"把原型当成了产品"的问题,也正是 Majorbird 要帮你避开的坑。
一份协议,多家网关
设计思路很简单:不管后端接的是哪家支付网关,Odoo POS 只讲一种中立语言。收银端只面对一份精简的 HTTP 协议,词汇表很小:支付(传入订单号、金额、扫码内容、目标网关)、查询或轮询、退款、撤销,再加一个原始代理接口,留给极少数特殊情况。
支付状态被归一到同一套标准:已创建、支付中、已支付/失败/已取消,然后进入退款中、已退款/部分退款。那些繁杂的提供商细节,签名算法、字段名、金额格式、请求地址,全部被隔离在每个网关的独立模块里,藏在注册表之后。
这才是"一个插件,多个网关"的落地方式,不是一句口号。Odoo 的支付方式配置里,只存一个端点地址和选用的网关。新增一家提供商,只需一个新模块加注册表里的一行代码。POS 插件本身不动,不用重构,不用 fork,不用为每个客户单独打包。
中国 POS 支付,为什么是个独特难题
实话实说,这比接一套欧美卡组织网关要复杂得多,而且复杂的地方往往出人意料。
流程是反过来的。不是顾客扫商家的收款码,而是收银员扫顾客手机上的付款码。这叫顾客被扫模式,也就是 micropay 流程。
响应往往不是即时的。一笔扣款可能秒过,也可能卡在顾客输密码的环节,返回"用户支付中"的状态。没有同步的 Yes 或 No,你必须轮询等到结果落定。同样关键的是,"系统繁忙"或"用户仍在支付"这类模糊响应,绝不能当成失败处理。因为一笔其实已经成功的订单,如果你重试,就会重复扣款。超时仍卡在"支付中"的订单,必须自动撤销,不能让资金悬在半空。
对账需要自己的账本。网关只回答单笔交易,没有"列出今日销售"的接口可用,所以系统要留下持久化记录,并以此为基准去核对。而在统一协议的背后,两家提供商其实是两个世界:WeChat Pay v2 用 XML,MD5 签名,退款还要客户端 TLS 证书;Alipay 用 JSON,RSA2 签名。中立协议的意义就在于:收银员和 Odoo POS,永远不需要知道这些。
从临时脚本到可运营服务
把这套东西变成能服务成百上千商户的系统,靠的不是黑科技,而是把常规的软件工程纪律执行到位。网关作为版本化服务运行,镜像标签不可变,测过的是什么,上线的就是什么。配置优于代码:凭证和网关列表来自环境变量,敏感信息不写死,密钥在启动时从 Vault 拉取,而不是打包进发布包。签名逻辑有单元测试覆盖。系统自带持久化账本、后台对账兜底机制、运维看板、自验证备份。新商户入驻变成一张 checklist,不再是重构一次代码。
门店端感受到的是什么
对零售商来说,最终体验应该是"无感"的,这正是我们要的。你在 Odoo POS 上直接收 WeChat Pay 和 Alipay,实时确认、实时退款,交易自动对账进 Odoo,不用每天下班后再派人手工核对支付 App 的总额和销售单。新增一家支付服务商,不需要定制开发。多门店、多客户上线更快,维护成本更低,支付流水端到端可审计。
目前 POS 插件面向 Odoo 18 Enterprise POS,而网关服务本身与 Odoo 版本解耦。Odoo 19 的适配已在计划中。
我们的观点
接中国支付通道本身不难,几乎任何人都能让单笔交易跑通一次。难的是让每一家门店、每一家服务商、每一次系统升级,都用同一套方案稳定运行,不用每次都重建,也不会埋下重复扣款的雷。这就是"Demo 能跑"和"生产能扛"的区别,也是 Majorbird 在 Odoo 实施中一贯坚持的:先诊断,再搭建。
如果你正在考虑如何在 Odoo POS 上接入 WeChat Pay 和 Alipay,或者你手上那个临时拼凑的集成已经开始让你头疼,那最好在它彻底崩掉之前,先聊聊。联系 Majorbird: odoo@majorbird.com 或 www.majorbird.cn。