在 kiosk 自助点餐场景里,最危险的误判就是把支付终端当成“返回成功就行”的黑盒。企业版 pos_self_order_iot 其实把终端回调拆成了三件事:校验 POS 配置 access token、定位订单、把结果通过 IoT 通道回送到 kiosk 页面。
主要参考源码:
enterprise/pos_self_order_iot/models/pos_payment_method.pyenterprise/pos_self_order_iot/controllers/orders.py
一、付款发起时,支付方式就已经带上了 IoT 能力判断
_payment_request_from_kiosk() 的关键不是复杂逻辑,反而是那个简单的分支:如果支付方式挂了 iot_device_id,前端就按 IoT 终端流程处理,否则走父类逻辑。也就是说,自助收银是否能走终端支付,在发起时已经按支付方式被分流。
二、成功与取消回调都必须重新绑定订单
iot_payment_success() 和 iot_payment_cancelled() 都先通过 access_token 验证 POS 配置,再按 order_id + config_id 找订单。成功回调会补一条 payment、写入卡种、交易号和小票,再执行 action_pos_order_paid();取消回调则明确给订单发送失败结果。
这里跨了:
- self-order 网站入口;
- POS 订单;
- 支付终端回执;
- POS 正式收款过账。
三、为什么 websocket 通道不是可有可无
iot_box_websocket_channel() 在 access token 有效时返回 IoT channel,并支持把消息推过去;POS 已关闭时则直接返回空字符串。这个设计说明 kiosk 页面不是被动等 HTTP 结果,而是需要一个持续通道把终端动作和状态推回前端。
如果没有这层通道,成功/失败就只能靠轮询,体验和一致性都会变差。
四、这条链路真正保护了什么
- 防串单:同一个终端回调不能随便落到别的 POS 配置订单上;
- 防假成功:只有写入 payment 并执行
action_pos_order_paid(),订单才进入已付链; - 防前端悬空:成功/失败结果都能回推到 kiosk 页面。
五、结论
kiosk IoT 支付不是“终端成功回调一下就行”,而是access token 校验 -> 订单绑定 -> payment 过账 -> websocket 回推四段闭环。少任何一段,都会出现串单、假成功或前端卡死的问题。
DISCUSSION
评论区