在前文 国外支付对接 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/Createsectionlabel for amountspan class input-label Amount /spandiv class input-wrapper amount-wrapperinput id amount name amount type tel min 0.01 placeholder Amount value 0.01/div/labeldiv class bt-drop-in-wrapperdiv id bt-dropin /div/div/sectioninput 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 /scriptscript$(function () { var client_token ViewBag.ClientTokenvar form document.querySelector( #payment-formbraintree.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: CVVpostalCode: { 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 submit document.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(); 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 Declinedreturn 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。

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