You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo 18 JS:如何正确扩展原生payment_paypal模块以启用PayLater功能?

Odoo 18 JS:如何正确扩展原生payment_paypal模块以启用PayLater功能?

我完全懂你现在的处境——想给Odoo的PayPal支付加PayLater选项,可要么改了之后其他支付方式炸了,要么PayPal SDK重复加载出问题。下面给你两个靠谱的方案,按需选就行:

方案一:精准扩展PayPal逻辑(推荐,与原代码耦合度低)

这个方案会完整保留原模块的所有功能(包括其他支付方式的处理),只针对PayPal的SDK URL和初始化逻辑做修改,从根源避免SDK重复加载:

import paymentForm from '@payment/js/payment_form';
import loadJS from '@web/core/assets/load_js';

paymentForm.include({
    async _prepareInlineForm(providerId, providerCode, paymentOptionId, paymentMethodCode, flow) {
        // 非PayPal支付方式直接走原逻辑,确保Stripe等功能不受影响
        if (providerCode !== 'paypal') {
            this._super(...arguments);
            return;
        }

        // 以下完全复用原PayPal模块的核心逻辑,仅修改SDK URL和PayLater相关配置
        this._hideInputs();
        this._setPaymentFlow('direct');
        document.getElementById('o_paypal_button').classList.remove('d-none');
        document.getElementById('o_paypal_loading').classList.remove('d-none');

        this.paypalData ??= {};
        const currentPayPalData = this.paypalData[paymentOptionId];

        if (this.selectedOptionId && this.selectedOptionId !== paymentOptionId) {
            this.paypalData[this.selectedOptionId]['paypalButton'].hide();
        }

        if (currentPayPalData && this.selectedOptionId !== paymentOptionId) {
            let paypalSDKURL = this.paypalData[paymentOptionId]['sdkURL'];
            // 给已有的SDK URL补全PayLater参数
            if (!paypalSDKURL.includes('enable-funding=paylater')) {
                paypalSDKURL += (paypalSDKURL.includes('?') ? '&' : '?') + 'enable-funding=paylater&components=buttons,messages';
            }
            const paypalButton = this.paypalData[paymentOptionId]['paypalButton'];
            await loadJS(paypalSDKURL);
            paypalButton.show();
        } else if (!currentPayPalData) {
            this.paypalData[paymentOptionId] = {};
            const radio = document.querySelector('input[name="o_payment_radio"]:checked');
            if (radio) {
                this.inlineFormValues = JSON.parse(radio.dataset['paypalInlineFormValues']);
                this.paypalColor = radio.dataset['paypalColor'];
            }

            const { client_id, currency_code } = this.inlineFormValues;
            // 生成包含PayLater支持的SDK URL
            const paypalSDKURL = `https://www.paypal.com/sdk/js?client-id=${client_id}&components=buttons,messages&currency=${currency_code}&intent=capture&enable-funding=paylater`;
            
            await loadJS(paypalSDKURL);
            const paypalButton = paypal.Buttons({
                fundingSource: paypal.FUNDING.PAYPAL,
                style: {
                    color: this.paypalColor,
                    label: 'paypal',
                    disableMaxWidth: true,
                    borderRadius: 6,
                },
                createOrder: this._paypalOnClick.bind(this),
                onApprove: this._paypalOnApprove.bind(this),
                onCancel: this._paypalOnCancel.bind(this),
                onError: this._paypalOnError.bind(this),
            });

            this.paypalData[paymentOptionId]['sdkURL'] = paypalSDKURL;
            this.paypalData[paymentOptionId]['paypalButton'] = paypalButton;
            paypalButton.render('#o_paypal_button');

            // 可选:添加PayLater分期信息条(如果需要展示)
            paypal.Messages({
                style: { layout: 'text' } // 可选text/flex/vertical三种布局
            }).render('#o_paypal_messages');
        }

        document.getElementById('o_paypal_loading').classList.add('d-none');
        this.selectedOptionId = paymentOptionId;
    },
});

方案说明

  • 保留了原方法对非PayPal支付方式的处理,确保其他支付渠道正常工作
  • 仅修改PayPal相关逻辑中的SDK URL,添加enable-funding=paylater(启用PayLater)和components=buttons,messages(加载分期信息组件)两个关键参数
  • 完全复用原模块的按钮状态管理、SDK加载判断逻辑,从根源避免重复加载问题

方案二:全局拦截SDK加载请求(更简洁,适合快速实现)

如果你不想复制太多原模块代码,可以通过拦截loadJS函数自动修改PayPal SDK的请求参数,完全不改动原模块的核心逻辑:

import paymentForm from '@payment/js/payment_form';
import loadJS from '@web/core/assets/load_js';

// 保存原始的loadJS函数
const originalLoadJS = loadJS;

// 重写loadJS,自动给PayPal SDK添加PayLater参数
window.loadJS = async function(url, options) {
    if (url.startsWith('https://www.paypal.com/sdk/js')) {
        // 解析并修改URL参数
        const [baseURL, paramStr] = url.split('?');
        const params = new URLSearchParams(paramStr || '');
        
        // 启用PayLater
        params.set('enable-funding', 'paylater');
        // 确保包含messages组件(用于展示分期信息)
        const components = (params.get('components') || 'buttons').split(',');
        if (!components.includes('messages')) {
            components.push('messages');
            params.set('components', components.join(','));
        }

        // 重新拼接修改后的URL
        url = `${baseURL}?${params.toString()}`;
    }
    // 调用原始函数加载资源
    return originalLoadJS(url, options);
};

// 无需修改_prepareInlineForm,原模块逻辑会自动使用修改后的SDK URL
paymentForm.include({});

方案说明

  • 通过全局拦截loadJS函数,自动处理所有PayPal SDK的请求,无需修改原模块的任何业务逻辑
  • 即使原模块后续更新,只要它还是用loadJS加载SDK,你的PayLater功能就依然有效
  • 仅针对PayPal的SDK URL生效,不会影响其他资源的加载

最后提醒

不管用哪个方案,记得先在PayPal商家后台开启PayLater选项,并确保你的PayPal账户支持该功能。测试前清理浏览器缓存,确保新的SDK配置被正确加载。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 07:13:04