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

【PayPal支付开发(Vue.js -- node.jsKoa2)】补充一下:想选择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 = https://www.it610.com/article/{
//注意:你的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

    推荐阅读