当前位置: 首页 > 工具软件 > jwt-node-vue > 使用案例 >

PayPal支付开发(Vue.js -- node.jsKoa2)

魏波娃
2023-12-01

补充一下:想选择Paypal做支付的,慎选,由于网络服务器网速原因访问部分网站网速极其的慢,他的支付网站还设置timeout过时,导致跳转到他的支付页 资源都没全部拉取下来就timeout掉了。有段时间情况好一点,有段时间完全不能访问!

注:找了个韩国的VPN网络测速正常。可能跟国内外网络封锁有很大关系!

开发者中心地址:https://developer.paypal.com/developer/applications/

开发文档:https://developer.paypal.com/docs/api/quickstart/payments/#additional-information

开发文档为多种语言提供测试demo。

1.进入开发者中心注册一个账户用于测试。Sandbox用于测试API里面有虚拟货币用于支付,Live真实支付环境。

在Sandbox下 CreateApp创建一个项目。

拿到Client ID与Secret。准备工作就以上这么多。

一:开发步骤

    //安装paypal依赖库
    cnpm install paypal-rest-sdk

二:创建configuration文件。

    var paypal = require('paypal-rest-sdk');
     
    paypal.configure({
        'mode': 'sandbox', //sandbox or live
        'client_id': '填入刚刚申请的client Id',
        'client_secret': '填入刚刚申请的secret'
    })

三:准备请求接口。

    /**
     * (新)实体商品Paypal支付
     */
    router.post('/getPaymentPhysical', controllPayPal.getPaymentPhysical)
     
    /**
     * (新)实体商品支付成功回调创建订单!
     */
    router.get('/PaymentSucceedPhysical', controllPayPal.PaymentSucceedPhysical)

四:业务层

    const PayPalImpl = require('../src/PayPalImpl')
    const utils = require('../resource/utils')
    const jwt = require("jsonwebtoken")
    const config = require('../config')
     
    /**
     * 商品支付
     * @param {*} ctx
     */
    async function getPaymentPhysical(ctx) {
        //商品参数信息
        var create_payment_json = JSON.stringify({
            intent: 'sale',
            payer: {
                payment_method: 'paypal'
            },
            redirect_urls: {//return_url支付成功回调  cancel_url取消支付返回跳转地址。
                return_url: "http://mychen.vip:3001/petshop/v1/api/PaymentSucceedPhysical?orderContent=" + ctx.request.body.orderContent,
                cancel_url: "http://127.0.0.1:8081/#/PhysicalProductDetails"
            },
            transactions: [{ //amount 对象 跟item_list对象要注意一下,下面前端页集成数据结构有详细描述
                amount: {
                    total: ctx.request.body.totalPrice,
                    currency: 'USD',
                    details: {
                        subtotal: ctx.request.body.subtotal,
                        tax: ctx.request.body.tax
                    }
                },
                description: '支付测试!',
                // invoice_number: '485787589673',
                payment_options: {
                    allowed_payment_method: 'INSTANT_FUNDING_SOURCE'
                },
                item_list: {
                    items: ctx.request.body.items
                }
            }]
        });
        await PayPalImpl.getPaymentImpl(create_payment_json).then(res => {
            console.log(res)
            ctx.body = res
        })
    }
     
    /**
     * 商品支付成功回调创建订单
     */
    async function PaymentSucceedPhysical(ctx) {
        var paymentId = ctx.query.paymentId;
        var payerId = { payer_id: ctx.query.PayerID };
        var insertStr = jwt.verify(ctx.query.orderContent, config.secret2);
        for (var i = 0; i < insertStr.length; i++) {
            insertStr[i].physicalOrderId = utils.generateProductId("");   //订单id
            insertStr[i].paymentId = paymentId;
            insertStr[i].payerId = payerId.payer_id;
            insertStr[i].Status = 101;
            insertStr[i].findStatus = 0;
            insertStr[i].createTime = utils.getTime();
            insertStr[i].userOpenId = jwt.verify(insertStr[i].userOpenId, config.secret)
        }
        console.log(insertStr)
        await PayPalImpl.PaymentSucceedPhysicalImpl(paymentId, payerId, insertStr).then(res => {
            ctx.response.redirect("http://127.0.0.1:8081/#/PhysicalProductDetails")
        })
    }

五:逻辑层

    var paypal = require('paypal-rest-sdk');
    require('../configuretion');
    const MongoClient = require('mongodb').MongoClient
    const config = require('../config');
     
    async function getPaymentImpl(create_payment_json) {
        return new Promise((resolv) => {
            //打开付款页面
            paypal.payment.create(create_payment_json, function (error, payment) {
                var links = {};
                if (error) {
                    console.error(JSON.stringify(error));
                    resolv({ code: 201, msg: '请求失败!', url: "" })
                } else {
                    // Capture HATEOAS links
                    payment.links.forEach(function (linkObj) {
                        links[linkObj.rel] = {
                            href: linkObj.href,
                            method: linkObj.method
                        };
                    })
                    // If redirect url present, redirect user
                    if (links.hasOwnProperty('approval_url')) {
                        // REDIRECT USER TO links['approval_url'].href;
                        console.log(links.approval_url.href)
                        resolv({ code: 200, msg: '请求成功!', url: links.approval_url.href })
                    } else {
                        console.error('no redirect URI present');
                        resolv({ code: 201, msg: '请求失败!', url: "" })
                    }
                }
            });
        })
    }
     
    async function PaymentSucceedPhysicalImpl(paymentId, payerId, insertStr) {
        return new Promise((resolv) => {
            paypal.payment.execute(paymentId, payerId, function (error, payment) {
                if (error) {
                    console.error(JSON.stringify(error));
                } else {
                    if (payment.state == 'approved') {
                        console.log('payment completed successfully');
                        MongoClient.connect(config.Mongose.url, { useNewUrlParser: true }, function (err, db) {
                            if (err) throw err;
                            var dbo = db.db("petshop");
                            dbo.collection('physicalOrders').insertMany(insertStr, function (err, res) {
                                if (err) throw err;
                                db.close();
                                resolv({ code: 200, msg: "付款成功!" });
                            })
                        })
                    } else {
                        console.log('payment not successful');
                        resolv({ code: 201, msg: "付款失败!" })
                    }
                }
            })
        })
    }

六:前端集成支付数据。

        onSubmit() {
            if(this.addressContent) {
                Toast.loading({
                    mask: true,
                    message: "正在跳转三方支付网站!请勿操作!"
                });
                console.log(this.orderContent)
                console.log(this.addressContent)
                var contents = [{//这个是我的订单数据结构,订单数据结构按自己维护为准。之所以用数组是为了方便以后购物车多商品支付。
                    userOpenId: JSON.parse(localStorage.getItem("userInfo")).openId,
                    openId: this.orderContent.openId,
                    ShopName: this.$store.state.StoreDetails.ShopName,
                    paymentAmount: this.orderContent.Price,
                    freight: this.orderContent.trafficPrice,
                    comAmount: 1,
                    consignee: this.addressContent,
                    orders: [{productId:this.orderContent.productId,sum:this.value}]
                }]
                var data = {
    //注意:你的items参数中的price值一定要与支付金额一致否则getPaymentPhysical接口执行出错。
                    totalPrice: this.orderContent.Price+this.orderContent.trafficPrice,
                    subtotal: this.orderContent.Price+this.orderContent.trafficPrice,
                    tax: 0,
                    items: [{
                        name: this.orderContent.productName,//商品名称
                        quantity: this.value.toString(), //商品数量
                        price: this.orderContent.Price, //商品价格
                        tax: '0',   //税率,建议不要维护税率直接给0后台自己记录税率问题就好了。PayPal税率结算机制我没弄懂,生成支付路径一直报错。
                        sku: this.orderContent.productTaste,
                        currency: 'USD'
                    },{
                        name: '运费',
                        quantity: '1',
                        price: this.orderContent.trafficPrice,
                        tax: '0',
                        sku: '运费',
                        currency: 'USD'
                    }],
                    orderContent: this.$jwt.sign(JSON.stringify(contents), this.$secretKey)
                }
                console.log(contents)
                console.log(data)
                this.$Request_post(this.$request + '/getPaymentPhysical', data).then(res => {
                    console.log(res)
                    window.location.replace(res.data.url)
                })
            } else {
                console.log("请去添加您的收货地址")
                Dialog.confirm({
                    title: '提示!',
                    message: '您还没有添加您的收货地址!'
                }).then(() => {
                    this.$router.push({
                        name: "AddConsignee"
                    })
                }).catch(() => {
                    // on cancel
                        console.log("取消")
                    });
                }
        },

注意:你的items参数中的price值一定要与支付金额一致否则getPaymentPhysical接口执行出错。

再次申明:contents与orderContent是个人维护的数据结构,订单信息最好按自己系统要求满足。

同时关于支付成功的回调接口只能用get请求。(重点要考的)但是可以携带参数比如 ?productId=123456

PayPal支付跳转时跟网络环境也有很大关系,国内外网络限速会导致跳转时经常出现连接超时。
————————————————
版权声明:本文为CSDN博主「一个头发贼多的小火鸡」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42172829/article/details/103257854

 类似资料: