Odoo前端JS函数重写疑问:如何覆盖payment_transaction_poll_status?
你的判断完全正确!website_sale.validate模块确实没有导出任何可供include方法使用的对象,这就是你调用website_sale_validate.include({...})时出现TypeError: Cannot read property 'include' of undefined的原因。原模块的代码完全封装在odoo.define的回调函数中,所有内部函数(包括payment_transaction_poll_status)都是局部变量,外部模块无法直接通过常规的Odoo模块继承机制访问或修改它们。
可行的重写方法
1. 覆盖原模块定义(直接但需同步原代码)
你可以重新定义website_sale.validate模块,将原模块的代码完整复制过来,然后修改payment_transaction_poll_status函数的逻辑。这种方法需要确保你的模块在原模块之后加载(通过在__openerp__.py中声明依赖website_sale),这样你的模块会覆盖原模块的定义。
示例代码(/test/static/src/js/test.js):
odoo.define('website_sale.validate', function(require) { "use strict"; // 复制原website_sale.validate模块的所有代码 // ... 原模块中的其他逻辑(比如依赖引入、DOM元素获取等) $(document).ready(function () { // ... 原模块中的其他局部函数和逻辑 // 重写目标函数 function payment_transaction_poll_status() { // 你的自定义轮询逻辑 console.log("Custom payment poll running..."); // 如果需要保留原逻辑,可以复制原函数的代码并修改 // 原逻辑示例:检查支付状态、更新UI、设置下一次轮询等 // 继续轮询(根据需求调整延迟时间) setTimeout(payment_transaction_poll_status, 3000); } // 启动自定义轮询 payment_transaction_poll_status(); }); });
注意:这种方法的缺点是原模块更新后,你需要同步复制最新的代码,否则会丢失原模块的新功能。
2. 拦截定时器替换轮询逻辑
如果原payment_transaction_poll_status函数使用setTimeout或setInterval实现循环轮询,你可以通过重写全局的定时器函数,记录原轮询的定时器ID,然后清除它并启动自己的自定义轮询。
示例代码:
odoo.define('test.test', function(require) { "use strict"; // 保存原生setTimeout const originalSetTimeout = window.setTimeout; let originalPollTimerId = null; // 重写setTimeout,捕获原轮询的定时器ID window.setTimeout = function(callback, delay) { const timerId = originalSetTimeout(callback, delay); // 通过函数名判断是否是目标轮询函数 if (callback.name === 'payment_transaction_poll_status') { originalPollTimerId = timerId; } return timerId; }; $(document).ready(function() { // 等待原轮询执行一次后,替换为自定义逻辑 setTimeout(() => { if (originalPollTimerId) { // 清除原定时器 clearTimeout(originalPollTimerId); // 启动自定义轮询 customPaymentPoll(); } }, 1000); }); // 自定义轮询函数 function customPaymentPoll() { // 你的自定义逻辑:比如调用API检查支付状态、更新页面UI等 console.log("Custom payment poll is running"); // 继续循环轮询(延迟时间和原函数保持一致或调整) originalSetTimeout(customPaymentPoll, 3000); } });
注意:这种方法依赖原函数的名称,如果原函数名被修改会失效,同时可能会影响其他使用setTimeout的代码,建议在调试确认后使用。
3. 通过DOM监听实现逻辑替代(无侵入式)
如果原轮询函数的主要作用是更新页面上的支付状态元素,你可以使用MutationObserver监听这些元素的变化,在状态更新时执行自定义逻辑,无需修改原函数。
示例代码:
odoo.define('test.test', function(require) { "use strict"; $(document).ready(function() { // 找到支付状态对应的DOM元素(根据原模块的实际选择器调整) const paymentStatusElement = $('#payment-transaction-status'); if (paymentStatusElement.length) { // 创建观察者对象 const statusObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // 当状态元素内容变化时,执行自定义逻辑 const currentStatus = paymentStatusElement.text().trim(); handlePaymentStatusUpdate(currentStatus); }); }); // 配置观察选项:监听子节点变化和文本内容变化 statusObserver.observe(paymentStatusElement[0], { childList: true, subtree: true, characterData: true }); } }); // 自定义状态处理逻辑 function handlePaymentStatusUpdate(status) { console.log("Payment status updated to:", status); // 根据状态执行不同操作:比如显示自定义提示、跳转页面等 if (status === 'paid') { alert("Payment successful! Redirecting..."); window.location.href = '/thank-you'; } } });
这种方法完全无侵入,不会影响原模块的逻辑,适合只需要根据状态变化执行额外操作的场景。
内容的提问来源于stack exchange,提问作者Pascal

