braintree支付开发
braintree介绍
流程介绍
-
前端从服务端请求一个客户端令牌,并初始化客户端SDK。
-
服务端SDK生成客户端令牌并将其发送回客户端
-
客户提交付款信息,客户端SDK将该信息传递给Braintree,并返回付款方式随机数
-
前端付款方式随机数发送给服务端
-
服务端收到付款方式随机数后,使用SDK向Braintree发起交易请求。
环境配置
注册Braintree帐号
-
前往braintree开发者文档注册沙盒帐号
-
登录后点击齿轮⚙==>API==>Keys==>APIKeys==>PrivateKey==>View 备用
BraintreeGateway gateway = new BraintreeGateway(Environment.SANDBOX,"f6tw2cm2c24yfbs7","ds8szsps6fc9tjky","bf4a3e7971a8e4be2dada2f7ca19573a" );
注册Paypal帐号
-
前往paypal开发者文档注册沙盒帐号
-
登录沙盒控制台后点击 My Apps & Credentials 选择 SandBox
-
创建app ---------- REST API apps下点击Create app
- 输入 App name
- Sandbox Business Account 选择一个business.example.com帐号
-
获取app参数备用--------点击进入app
#### Sandbox account #### luozong@business.example.com #### Client ID ##### ATN8f09gmB9Njm0iuoyApCV04GXbhbfltRzQPMHtjEL3i2oIZO0ShB31nIczY_hK1W0bVbYRUQaKIer6 #### Secret #### EGQzXV9F46OEBFBZHNkk04CAIXRwZW1r4K6X40anp2RKL4dYa4q-11qLxcuW1fyHZ-DA01Y9Oa_xC86j
设置braintree链接到paypal
-
前往braintree开发者文档登录braintree沙盒控制台
-
登录后点击齿轮==>Processing==>Processing Options==>Payment Methods==>Paypal==>Link Sandbox
-
进入到PayPal Sandbox Credentials ,填写以下信息
####PayPal Email##### luozong@business.example.com ####PayPal Client Id#### ATN8f09gmB9Njm0iuoyApCV04GXbhbfltRzQPMHtjEL3i2oIZO0ShB31nIczY_hK1W0bVbYRUQaKIer6 ####PayPal Client Secret#### EGQzXV9F46OEBFBZHNkk04CAIXRwZW1r4K6X40anp2RKL4dYa4q
点击 Link Paypal Sandbox 按钮
直接支付
公司的流程和代码不符合,看看流程就好
前端代码
参考官方Set Up Your Client
该例子创建了 信用卡支付、paypal支付
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><!--jquery为了调用服务端获取token--><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.2.1/jquery.min.js" crossorigin="anonymous"></script><!--braintree出信用卡要加--><script src="https://js.braintreegateway.com/web/dropin/1.23.0/js/dropin.min.js"></script><!--出paypal按钮要加--><script src="https://www.paypal.com/sdk/js?client-id=sb"></script><!--沙盒client-id=sb,pro client-id取paypal的clientID--><script src="https://js.braintreegateway.com/web/3.64.2/js/client.min.js"></script><script src="https://js.braintreegateway.com/web/3.64.2/js/paypal-checkout.min.js"></script><script>$(function(){//获取tonkenvar token = null;$.ajax({url:'/braintree/getToken',type:'post',success:function(data){token = data;},async:false});//渲染信用卡交易按钮var button = document.querySelector('#submit-button');//信用卡输入显示braintree.dropin.create({authorization: token,container: '#dropin-container'}, function (createErr, instance) {button.addEventListener('click', function () {instance.requestPaymentMethod(function (err, payload) {// Submit payload.nonce to your server//发送payload.nonce以及订单信息到服务端});});});// 创建paypal按钮代码braintree.client.create({authorization: token}, function (clientErr, clientInstance) {// Stop if there was a problem creating the client.// This could happen if there is a network error or if the authorization// is invalid.if (clientErr) {console.error('Error creating client:', clientErr);return;}// Create a PayPal Checkout component.braintree.paypalCheckout.create({client: clientInstance}, function (paypalCheckoutErr, paypalCheckoutInstance) {if(paypalCheckoutErr){console.error('Error creating paypalCheckoutInstance:', paypalCheckoutErr);}paypalCheckoutInstance.loadPayPalSDK({currency: 'USD',intent: 'capture'}, function () {paypal.Buttons({fundingSource: paypal.FUNDING.PAYPAL,createOrder: function () {//此处可以去服务端下订单,获取订单具体信息在放到createPayment里面return paypalCheckoutInstance.createPayment({flow: 'checkout', // Requiredamount: 10.00, // Requiredcurrency: 'USD', // Required, must match the currency passed in with loadPayPalSDKintent: 'capture', // Must match the intent passed in with loadPayPalSDK//地址信息enableShippingAddress: true,shippingAddressEditable: false,shippingAddressOverride: {recipientName: 'Scruff McGruff',line1: '1234 Main St.',line2: 'Unit 1',city: 'Chicago',countryCode: 'US',postalCode: '60652',state: 'IL',phone: '123.456.7890'}});},onApprove: function (data, actions) {return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {// Submit `payload.nonce` to your server//发送payload.nonce以及订单信息到服务端请求进行一次付款交易(transaction)});},onCancel: function (data) {console.log('PayPal payment cancelled', JSON.stringify(data, 0, 2));},onError: function (err) {console.error('PayPal error', err);}}).render('#paypal-button').then(function () {// The PayPal button will be rendered in an html element with the ID// `paypal-button`. This function will be called when the PayPal button// is set up and ready to be used});});});});});</script></head><body><div id="dropin-container"></div><button id="submit-button">Request payment method</button><div id="paypal-button"></div></body>
</html>
后端代码
//简单的gatway配置,来自braintree帐号
public class GatewayFactory {public static BraintreeGateway getlisiGateway() {BraintreeGateway gateway = new BraintreeGateway(Environment.SANDBOX,"f6tw2cm2c24yfbs7", "ds8szsps6fc9tjky", "bf4a3e7971a8e4be2dada2f7ca19573a");return gateway;}
}
@RestController
@RequestMapping("/braintree")
public class BraintreeController {private static BraintreeGateway gateway = GatewayFactory.getlisiGateway();@PostMapping("/getToken")public String getToken(){//官方写new ClientTokenRequest().customerId("customerId")可以不要。ClientTokenRequest clientTokenRequest = new ClientTokenRequest();String clientToken = gateway.clientToken().generate(clientTokenRequest);return clientToken;}//从前端获取的交易信息不只有nonce,还有金额,设备等,orderId也可以传@PostMapping("/pay")public Msg pay(String nonce) {TransactionRequest request = new TransactionRequest().amount(new BigDecimal("10.00")).paymentMethodNonce(nonce).deviceData("h5").options().submitForSettlement(true).done();Result<Transaction> result = gateway.transaction().sale(request);if(result.isSuccess()){return Msg.ok(result.getTarget().getStatus().toString());}else{return Msg.fail(result.getMessage());}}
}
坑点
- 官方写new ClientTokenRequest().customerId(“customerId”)可以不要。
- Transaction状态会自动转,算是官方的审核时间,自动的。
- 信用卡 submit_for_settlted 后续过30分钟自动转为 settlted
- paypal settlting 后续过30分钟自动转为 settlted
订阅支付
公司的流程和代码不符合,看看流程就好
前端代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.2.1/jquery.min.js" crossorigin="anonymous"></script><!--信用卡支付--><script src="https://js.braintreegateway.com/web/dropin/1.23.0/js/dropin.min.js"></script><!--paypal支付--><script src="https://js.braintreegateway.com/web/3.64.2/js/client.min.js"></script><script src="https://js.braintreegateway.com/web/3.64.2/js/paypal-checkout.min.js"></script><script src="https://www.paypal.com/sdk/js?client-id=sb&vault=true"></script><script>$(function(){var token = null;$.ajax({url:'/braintree/getToken?'+new Date().getTime(),type:'post',success:function(data){token = data;},async:false});alert(token);var button = document.querySelector('#submit-button');braintree.dropin.create({authorization: token,container: '#dropin-container'}, function (createErr, instance) {button.addEventListener('click', function () {instance.requestPaymentMethod(function (err, payload) {// Submit payload.nonce to your serverif(confirm("是否继续支付0.01USD?")){$.ajax({url:'/braintree/pay?'+new Date().getTime(),type:'post',data:'nonce='+payload.nonce,success:function(data){alert(data.msg);}});}});});});// Create a client.braintree.client.create({authorization: token}, function (clientErr, clientInstance) {alert(clientInstance);// Stop if there was a problem creating the client.// This could happen if there is a network error or if the authorization// is invalid.if (clientErr) {console.error('Error creating client:', clientErr);return;}// Create a PayPal Checkout component.braintree.paypalCheckout.create({client: clientInstance}, function (paypalCheckoutErr, paypalCheckoutInstance) {if(paypalCheckoutErr){console.error('Error creating paypalCheckoutInstance:', paypalCheckoutErr);}paypalCheckoutInstance.loadPayPalSDK({currency: 'USD',intent: 'capture',vault: true}, function () {paypal.Buttons({fundingSource: paypal.FUNDING.PAYPAL,createBillingAgreement: function () {return paypalCheckoutInstance.createPayment({flow: 'vault' // Required});},onApprove: function (data, actions) {return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {// Submit `payload.nonce` to your serverdebugger;if(confirm("是否继续支付10.00USD?")){$.ajax({url:'/braintree/pay2?'+new Date().getTime(),type:'post',data:'nonce='+payload.nonce,success:function(data){alert(data.msg);}});}});},onCancel: function (data) {console.log('PayPal payment cancelled', JSON.stringify(data, 0, 2));},onError: function (err) {console.error('PayPal error', err);}}).render('#paypal-button').then(function () {// The PayPal button will be rendered in an html element with the ID// `paypal-button`. This function will be called when the PayPal button// is set up and ready to be used});});});});});</script></head><body><div id="dropin-container"></div><div id="paypal-button"></div><button id="submit-button">Request payment method</button></body>
</html>
后端代码
@RestController
@RequestMapping("/braintree")
public class BraintreeController {private static BraintreeGateway gateway = GatewayFactory.getlisiGateway();@PostMapping("/getToken")public String getToken(){ClientTokenRequest clientTokenRequest = new ClientTokenRequest();String clientToken = gateway.clientToken().generate(clientTokenRequest);return clientToken;}@PostMapping("/pay2")public Msg pay2(String nonce) {//保存用户CustomerRequest customerRequest = new CustomerRequest().id(UUID.randomUUID().toString()).paymentMethodNonce(nonce).firstName("Fred").lastName("Jones").creditCard().done();Result<Customer> customerResult = gateway.customer().create(customerRequest);Customer customer = gateway.customer().find(customerResult.getTarget().getId());String token = customer.getDefaultPaymentMethod().getToken();SubscriptionRequest subscriptionRequest = new SubscriptionRequest().planId("jhk2").paymentMethodToken(token);Result<Subscription> result = gateway.subscription().create(subscriptionRequest);if(result.isSuccess()){return Msg.ok(result.getTarget().getStatus().toString());}else{return Msg.fail(result.getMessage());}}
}
坑点
-
订阅如果一直被declined 2046,表示帐号有问题,需要重新注册。我郁闷了好几天,最后重新注册就好了。