在前文 国外支付对接:Braintree(一)的基础上   已经拿到了相关配置信息,接下来就是码代码了,这里完成的主要功能是支付与退款。

在此之前,先说一下Briantree的支付流程:

第一步先生成clientToken,一组根据 MerchantId,BraintreePublicKey,BraintreePrivateKey生成的字符串,用于前端生成初始化支付控件。第二步点击支付按钮客户输入用户名密码确定支付之后,Briantree在前端会返回nonce给我们(相当于支付授权凭证)。第三步,将nonce传到后台,我们进行扣款。至此支付完成。

1.项目引用

  • 后端

从官方下载的demo中可以看到,其实我们的后端需要用的dll就是一个:Braintree.dll,NUGET上也能下载

  • 前端

需要的就是引用官方js,这个需要看个人需求吧,如果你不想麻烦自己写样式,可以直接使用官方的js生成的支付按钮,那么用drop-in UI即可。使用drop-in是最直接便利的方式,我们在前端直接引用:

<script src="https://js.braintreegateway.com/web/dropin/1.9.2/js/dropin.min.js"></script>

生成的样式长这样:

如果需要自己设计样式,按照自己的规则来控制前端的话,那就得使用Customer UI。那当然需要引用的js就不同了,前端的写法也就不同了,后面细说。这块主要的js是

<script src="https://js.braintreegateway.com/web/3.29.0/js/client.min.js"></script>

2.代码解析

  • web.config配置

API keys 拿到之后需要在程序中使用,我们直接配置在web.config中即可,当然安全着想也可以加密配置到数据库中。

  • 前端(这里先介绍使用drop-in UI的写法)

html:
   form只需要2个参数amount,nonce。最重要的是要定义一个div控件给生成支付控件使用,这里使用的id为bt-dropin的div

<form id="payment-form" method="post" action="/checkouts/Create"><section><label for="amount"><span class="input-label">Amount</span><div class="input-wrapper amount-wrapper"><input id="amount" name="amount" type="tel" min="0.01" placeholder="Amount" value="0.01"></div></label><div class="bt-drop-in-wrapper"><div id="bt-dropin"></div></div></section><input id="nonce" name="payment_method_nonce" type="hidden" /><button class="button"  type="submit"><span>Test Transaction</span></button></form>

js:

<script src="https://js.braintreegateway.com/web/dropin/1.9.2/js/dropin.min.js"></script>
<script>$(function () {var client_token = "@ViewBag.ClientToken";var form = document.querySelector('#payment-form');braintree.dropin.create({//支付控件初始化开始authorization: client_token,//由后端传过来的值,一组根据 MerchantId,BraintreePublicKey,BraintreePrivateKey生成的字符串container: '#bt-dropin',paypal: {flow: 'vault',buttonStyle: {  //可以修改一点点按钮的样式,限制性很多color: 'black',shape: 'rect',size: 'medium'}},//此处与上面的paypal设置不一样,亲么可以自己去尝试一下,不同点在哪//paypal: {//    flow: 'checkout',//    amount: document.querySelector('#amount').value,//    currency: 'USD'//}, card: {//此项选填,干掉也没关系cardholderName: { required: true }, //必填的话,就会多生成一个持卡人姓名的输入框overrides: {fields: {number: {placeholder: 'Card Number',},cvv: {placeholder: 'CVV'},postalCode: {placeholder: 'Postal Code'}},}},//threeDSecure: {//3D安全校验,选填,用于信用卡支付的时候,若改卡的持卡人在开卡的时候启用了额外的身份校验,例如密码,那么点支付的时候则会弹出一个额外的框,输入密码。//    amount: document.querySelector('#amount').value//}}, function (createErr, instance) {form.addEventListener('submit', function (event) {event.preventDefault();instance.requestPaymentMethod(function (err, payload) {//客户输入密码等之后,接收返回的结果,即nonce,支付授权凭证if (err) {console.log('Error', err);return;}// Add the nonce to the form and submitdocument.querySelector('#nonce').value = payload.nonce;form.submit();});});});});
</script>一组根据 MerchantId,BraintreePublicKey,BraintreePrivateKey生成的字符串container: '#bt-dropin',paypal: {flow: 'vault',buttonStyle: {  //可以修改一点点按钮的样式,限制性很多color: 'black',shape: 'rect',size: 'medium'}},//此处与上面的paypal设置不一样,亲么可以自己去尝试一下,不同点在哪//paypal: {//    flow: 'checkout',//    amount: document.querySelector('#amount').value,//    currency: 'USD'//}, card: {//此项选填,干掉也没关系cardholderName: { required: true }, //必填的话,就会多生成一个持卡人姓名的输入框overrides: {fields: {number: {placeholder: 'Card Number',},cvv: {placeholder: 'CVV'},postalCode: {placeholder: 'Postal Code'}},}},//threeDSecure: {//3D安全校验,选填,用于信用卡支付的时候,若改卡的持卡人在开卡的时候启用了额外的身份校验,例如密码,那么点支付的时候则会弹出一个额外的框,输入密码。//    amount: document.querySelector('#amount').value//}}, function (createErr, instance) {form.addEventListener('submit', function (event) {event.preventDefault();instance.requestPaymentMethod(function (err, payload) {//客户输入密码等之后,接收返回的结果,即nonce,支付授权凭证if (err) {console.log('Error', err);return;}// Add the nonce to the form and submitdocument.querySelector('#nonce').value = payload.nonce;form.submit();});});});});
</script>
  • 后端

1.生成clientToken的规则有2种,根据需要来吧。

由于braintree平台中虽然只有一个商户ID,即Merchant ID,但是确可以有多个Merchant Accounts,即收账账号,设置的界面:Account-->Merchant Account Info

第一种,使用默认配置:

每个Merchant ID都会有一个default Merchant Account,所以下面的写法,就是默认将款额收到默认账户上

var config = new BraintreeGateway(environment, merchantId, publicKey, privateKey) ;
var gateway = config.GetGateway();
var clientToken = gateway.ClientToken.generate();

第二种:指另付款到某一个账号

var clientToken = gateway.ClientToken.generate(new ClientTokenRequest() { MerchantAccountId = "TestAccount" });

2.综合

支付功能:一共3个Action:

//生成clientToken 传到前端,用于生成支付控件
public ActionResult New(){        var gateway = config.GetGateway();//var clientToken = gateway.ClientToken.generate();var clientToken = gateway.ClientToken.generate(new ClientTokenRequest() { MerchantAccountId = "TestAccount" });ViewBag.ClientToken = clientToken;return View();}
//form提交,得到nonce之后,在这里进行扣款public ActionResult Create(){var gateway = config.GetGateway();Decimal amount;try{amount = Convert.ToDecimal(Request["amount"]);}catch (FormatException e){TempData["Flash"] = "Error: 81503: Amount is an invalid format.";return RedirectToAction("New");}var nonce = Request["payment_method_nonce"];//得到前端传来的nonce参数var request = new TransactionRequest//新建交易请求{MerchantAccountId = "TestAccount",//注意这里,如果你的clientToken生成的时候设置了MerchantAccountId,那么扣款的时候也必须要加上这个参数,否则是会失败的Amount = amount,PaymentMethodNonce = nonce,Options = new TransactionOptionsRequest{ThreeDSecure = new TransactionOptionsThreeDSecureRequest()//这里注意,如果你前端启用了3D安全,那么这里也需要启用{Required = true},SubmitForSettlement = true}};Result<Transaction> result = gateway.Transaction.Sale(request);//扣款if (result.IsSuccess())//成功{Transaction transaction = result.Target;//transaction.Id是官方生产的此交易的唯一编号,如果要进行查询和退款的话,就必须要将此ID记录数据库.return RedirectToAction("Show", new { id = transaction.Id });}else if (result.Transaction != null){return RedirectToAction("Show", new { id = result.Transaction.Id, mesg = result.Message});}else{string errorMessages = "";foreach (ValidationError error in result.Errors.DeepAll()){errorMessages += "Error: " + (int)error.Code + " - " + error.Message + "\n";}TempData["Flash"] = errorMessages;return RedirectToAction("New3");}}
//支付结果页展示
public ActionResult Show(String id, string mesg){var gateway = config.GetGateway();Transaction transaction = gateway.Transaction.Find(id);if (transactionSuccessStatuses.Contains(transaction.Status)){//成功}else{//失败}ViewBag.Transaction = transaction;return View();}

退款:

这里要说明下,即时客户完成了交易,已经进行了扣款,但是如果要立马退款的话,是不行的。因为braintree内部也要进行交易审核,审核过程需要时间,而且是时间不固定,可能十几分钟,可能几个小时。所以这里我们要根据当前退款的订单状态进行是退款还是作废。2种操作的过程是不一样的。退款会在briantree账户上生成退款交易单,但是作废不会,虽然2种操作最都会退款给客户。

 public ActionResult RefundTest(string trId, decimal amount){var gateway = config.GetGateway();try{Transaction transaction = gateway.Transaction.Find(trId);if (transaction.Status == TransactionStatus.SETTLED || transaction.Status == TransactionStatus.SETTLING){//交易状态为以上时,方可进行退款操作Result<Transaction> result = gateway.Transaction.Refund(trId, amount);if (!result.IsSuccess()){//退款失败//Transaction transaction = result.Transaction;//if (transaction.Status == TransactionStatus.SETTLEMENT_DECLINED)//{//    //Console.WriteLine(transaction.ProcessorSettlementResponseCode);//    // e.g. "4001"//    //Console.WriteLine(transaction.ProcessorSettlementResponseText);//    // e.g. "Settlement Declined"//}return RedirectToAction("RefundResponce", new { msg = result.Message });}else{return RedirectToAction("RefundResponce", new { msg = "OK" });}}else if (transaction.Status == TransactionStatus.AUTHORIZED || transaction.Status == TransactionStatus.SUBMITTED_FOR_SETTLEMENT ||(transaction.PaymentInstrumentType == PaymentInstrumentType.PAYPAL_ACCOUNT && transaction.Status == TransactionStatus.SETTLEMENT_PENDING)){//交易状态为此状态时不可退款,但是能void交易,即作废,那么就可同时退款可客户Result<Transaction> result = gateway.Transaction.Void(trId);if (result.IsSuccess()){return RedirectToAction("RefundResponce", new { msg = "transaction successfully voided" });}else{return RedirectToAction("RefundResponce", new { msg = result.Message });//foreach (ValidationError error in result.Errors.DeepAll())//{//    Console.WriteLine(error.Message);//}}}}catch(Exception ex){return RedirectToAction("RefundResponce", new { msg = ex.Message });}return RedirectToAction("RefundResponce");}//扣款结果显示
public ActionResult RefundResponce(string msg){ViewBag.Mesg = msg;return View();}

至此支付和退款功能完成。

其实还有很多需要解说和注意的地方,还是自己去多多摸索的话学到的更多。虽然都是英文的,可以锻炼英文的说。

关于自定义支付控件样式,即Customer UI的使用,下篇谈,官方介绍,有demo,还可以自己编码测试的网站

https://developers.braintreepayments.com/guides/hosted-fields/examples/javascript/v3。

Braintree-国外支付对接(三) 之Customer UI

以上纯属个人独自研究成果,仅供参考,转载请注明出处

Braintree-国外支付对接(二)相关推荐

  1. paypal braintree支付对接

    paypal本身有sdk,不过这里选择使用braintree服务进行对接,paypal本身也比较推荐这种方式. 准备工作 paypal账号 braintree账号(包括正式账号和沙盒账号) 申请流程这 ...

  2. Braintree-国外支付对接(一)

    前言:在国外,要说网上商城支付用的最多的就是Paypal和信用卡.Paypal相当于咱中国的支付宝,所以支付要对接它是必不可少的.在开发项目的初期最先对接的确是Paypal的Rest SDK,后来鉴于 ...

  3. Android平台招商银行“一网通”支付对接采坑记

    公司最近的App中需要做支付功能,支付中需要支持微信支付.支付宝支付.一网通支付.本文主要记录在对接Android平台中的"一网通"过程中遇到的坑,如果有类似需求的朋友,可供你参考 ...

  4. GlobalCash全球付万事达虚拟信用卡-可用于国外支付购物

    Via:http://www.freehao123.com/globalcash/ 前几天感恩节美国的主机域名商们都展开了一系列的优惠大降价活动,尤其是像Godaddy.Dreamhost.BlueH ...

  5. 小呆聚合支付源码开源修正版支持易支付对接各大网站,APP离线完美回调

    @全体成员v6.4.1升级到v6.4.2 1.增加两套支付模版,用户可以后台自由切换模式 2.优化默认支付模版,增加订单来源,商品名称 3.增加app在各个手机上安装指引教程 4.优化其他细节 @全体 ...

  6. 微信支付对接海关申报

    微信支付对接海关申报 1.先微信商户中心,进行海关申报配置 重点注意:请求接口前请先在以下页面提交您的海关信息,所有你需要报关的海关信息都需要提交 2.进行海关申报(本文章是没有子订单的) 注意:商户 ...

  7. JPA框架微信支付对接-V3支付接口,V2退款接口对接,复制即用

    框架:springDateJPA 对接微信支付首先需要需要在微信商户平台注册微信商户号 微信商户平台入口 微信公众平台入口 这里主要是微信支付的方式,一共有七种,我这里主要对接了3种,App支付,JS ...

  8. 微信二维码支付支付宝二维码支付(主扫模式)开发指南

    微信二维码支付 熟悉微信支付全家桶的童鞋应该都清楚,微信支付是没有提供PC网关支付的,那么传统的网站需要怎么接入微信支付产品呢? 我们可以选择微信支付中的Native支付产品,官方介绍: Native ...

  9. 服务端支付宝App支付对接笔记

    支付宝在2016年12月份开始将以前的App支付改为移动支付,而现在的App支付则是全新的支付,而功能和以前的App支付并没有太大的差别,但申请现在的App支付需要先废除掉以前的移动支付(控制台显示的 ...

最新文章

  1. LIVE 预告 | CVPR 2021 预讲 · 悉尼科技大学ReLER实验室专场
  2. 【C 语言】字符串模型 ( 字符串翻转模型 | 借助 递归函数操作 逆序字符串操作 | 引入线程安全概念 )
  3. 软件测试学习笔记:找代码中的fault,并设计特定的测试用例
  4. MATLAB保存当前窗口图像
  5. 一文详解 | 开放搜索兼容Elasticsearch做召回引擎
  6. war压缩命令_BetterZip mac版(超强解压缩软件)
  7. C#:生成哈希字符串
  8. Android入门 在ListView中如何进行精确的定位
  9. visio2003 反向工程链接 mssql2005
  10. DEM数据下载,拼接,裁剪
  11. Android——多功能记事本(Android Studio)
  12. 【GlobalMapper精品教程】003:影像裁剪、批量影像分幅案例详解
  13. 谷歌flash无法输入中文
  14. UI设计师的7大能力模型
  15. MATLAB_批量修改文件名称
  16. linux 进程共享内存同步,Linux使用共享内存通信的进程同步退出问题
  17. Web3.0技术栈简介
  18. 【MM小贴士】特殊采购类型40
  19. 20210514:廉价机械键盘学习
  20. Qt QSS QSlider样式

热门文章

  1. Sqldbx连接OracleX64位
  2. 计算机可以计算出十的一百次方吗,世界上最大的数字单位 古戈尔(1古戈尔等于10的100次方)...
  3. VS2017中MFC的C++设计中给其它窗口发中文消息
  4. opencv中的透射变换
  5. python turtle 海龟绘图详解(官方文档中文版)
  6. Python编程好不好学?入门难吗?
  7. python好学么零基础_python编程好学吗 自学行吗
  8. 【菜鸟C++学习杂记】ASCII码转换和显示
  9. 如何用PS制作一寸照片
  10. 电脑如何打开虚拟化设置?