Odoo14中如何实现控制器路由内Python函数调用JS函数
Odoo14 异步第三方回调触发前端逻辑方案
服务端无法直接主动调用浏览器端运行的JS函数,所有这类场景都需要通过前后端约定的数据通道传递信号,前端收到信号后自行触发对应逻辑。针对你的第三方支付异步回调场景,有两种可直接落地的成熟方案,根据业务场景选择即可。
方案一:前端短轮询(实现成本最低,无额外配置要求)
适合对实时性要求不高(1~3秒延迟可接受)的场景,不需要调整服务端部署配置,兼容性最好。
- 调整原有
do_payment_transaction方法逻辑:发起第三方API请求后不要同步等待回调结果,直接将当前交易记录的ID、初始状态(处理中)返回给前端,避免RPC请求超时。 - 自定义控制器收到第三方回调时,只需要根据交易标识匹配到对应的
atm.transaction记录,更新记录状态、存储回调数据即可,不需要额外处理前端逻辑。 - 前端拿到交易ID后启动定时轮询,间隔固定时间查询交易状态,直到状态变为终态(成功/失败)时清除定时器,执行后续业务逻辑。
JS参考代码:
this.rpc({ model: 'atm.transaction', method: 'do_payment_transaction', args: [customer_id], }).then(function (data) { const transactionId = data.transaction_id; // 启动轮询 const pollTimer = setInterval(() => { this.rpc({ model: 'atm.transaction', method: 'search_read', args: [[['id', '=', transactionId]], ['status', 'callback_result']], }).then(function (res) { const txInfo = res[0]; // 状态不是处理中说明已经收到第三方回调 if (txInfo.status !== 'processing') { clearInterval(pollTimer); console.log("获取到回调结果", txInfo.callback_result); // 此处编写你原本需要被触发的JS业务逻辑 } }) }, 1500); // 轮询间隔建议不小于1秒,避免给服务端造成过大压力 });
方案二:基于Odoo自带Bus长连接实现实时推送(实时性高)
适合对响应速度要求高的场景,Odoo14原生集成了长连接总线服务,不需要额外引入第三方组件。
- 模型侧新增通知方法,收到第三方回调更新交易状态后,通过bus向指定频道推送消息。
Python模型参考代码:
from odoo import models class AtmTransaction(models.Model): _name = 'atm.transaction' def push_callback_notify(self, callback_data): # 自定义频道规则,绑定交易所属用户和交易ID channel = (self.env.user.partner_id.id, 'atm_payment_callback', self.id) self.env['bus.bus'].sendone(channel, { 'tx_id': self.id, 'status': self.status, 'result': callback_data })
- 自定义控制器收到第三方回调、更新完交易记录后,调用上述
push_callback_notify方法推送通知即可。 - 前端在发起支付请求后订阅对应交易的通知频道,收到匹配的消息后执行后续逻辑,完成后取消订阅避免内存泄漏。
JS参考代码:
// 引入bus服务 const busService = require('bus.bus').bus; this.rpc({ model: 'atm.transaction', method: 'do_payment_transaction', args: [customer_id], }).then(function (data) { const txId = data.transaction_id; // 拼接当前交易对应的通知频道 const targetChannel = [this.session.partner_id.id, 'atm_payment_callback', txId]; // 订阅频道 busService.add_channel(targetChannel); // 监听通知 busService.on('notification', this, function (notifications) { notifications.forEach(notif => { const [channel, payload] = notif; if (JSON.stringify(channel) === JSON.stringify(targetChannel)) { console.log("实时收到回调结果", payload); // 此处编写你原本需要被触发的JS业务逻辑 // 执行完成后移除订阅 busService.delete_channel(targetChannel); busService.off('notification', this); } }) }) });
注意:使用该方案需要确认Odoo配置文件中
longpolling_port参数已正确配置,且服务启动时开启了至少1个worker进程,否则长连接服务不会生效。
不推荐方案
不建议自行接入额外WebSocket服务实现推送,会大幅增加部署、鉴权、连接维护的成本,上述两种方案已经可以覆盖绝大多数ATM支付场景的需求。
内容的提问来源于stack exchange,提问作者Douglas Tabut
相关产品推荐
相关产品推荐

