前篇:Braintree-國(guó)外支付對(duì)接(二) 中的支付按鈕的生成是braintree自帶的樣式和事件控制的,即drop-in,生成的界面我們不能過多的更改和控制。所以假如我們想要自己編寫控件,自己控制樣式,但又能正常點(diǎn)擊觸發(fā)支付等事件。那么就使用Customer UI.
使用Customer UI需要映入的官方JS有很大不同,但是我們的后端是不需要變的,因?yàn)樘峤坏膮?shù)和返回的參數(shù)是一樣的。下面給出的例子,沒有過多的寫的樣式很漂亮華麗,簡(jiǎn)單點(diǎn):
<div class="wrapper">
<div class="checkout container">
<header>
<h1>Hi,
<br>
Let's test a transaction</h1>
<p>
Make a test payment with Braintree using PayPal or a card
</p>
</header>
<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>
<fieldset>
<legend>Card</legend>
<div class="cardinfo-card-number">
<label class="cardinfo-label" for="cc-number">Card Number</label>
<div class='input-wrapper' id="cc-number"></div>
<div id="card-image"></div>
</div>
<div class="cardinfo-card-number">
<label class="cardinfo-label" for="cc-number">CVV</label>
<div class='input-wrapper' id="cc-cvv"></div>
</div>
<div class="cardinfo-card-number">
<label class="cardinfo-label" for="cc-expiration-date">Expiration-Date</label>
<div class='input-wrapper' id="cc-expiration-date"></div>
</div>
<button style="margin-top: 10px; background-color: pink;" class="button" id="card-button" type="button"><span style="padding: 0.7em 1em">Done</span></button>
</fieldset>
<fieldset>
<legend>Paypal</legend>
<button style="margin-top: 10px; background-color: pink;" class="button" disabled id="paypal-button" type="button"><span>Paypal</span></button>
<span id="payer"></span>
</fieldset>
</section>
<input id="nonce" name="payment_method_nonce" type="hidden" />
<button class="button" type="submit"><span>Test Transaction</span></button>
</form>
</div>
</div>
<style>
.cardinfo-card-number {position: relative;}
.cardinfo-label {
display: block;
font-size: 11px;
margin-bottom: 0.5em;
text-transform: uppercase;
}
.input-wrapper {
border-radius: 2px;
background: rgba(255, 255, 255, 0.86);
height: 2.75em;
border: 1px solid #eee;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.06);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.06);
padding: 5px 10px;
margin-bottom: 1em;
}
#card-image
{
position: absolute;
top: 36px;
right: 0px;
width: 44px;
height: 28px;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/346994/card_sprite.png);
background-size: 86px 458px;
border-radius: 4px;
background-position: -100px 0;
background-repeat: no-repeat;
margin-bottom: 1em;
}
#card-image.visa
{
background-position: 0 -398px;
}
#card-image.master-card
{
background-position: 0 -281px;
}
#card-image.american-express
{
background-position: 0 -370px;
}
#card-image.discover
{
background-position: 0 -163px;
}
#card-image.maestro
{
background-position: 0 -251px;
}
#card-image.jcb
{
background-position: 0 -221px;
}
#card-image.diners-club
{
background-position: 0 -133px;
}
</style>
<script src="\App_Themes\javascript\vendor\jquery-2.1.4.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.29.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.29.0/js/hosted-fields.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.29.0/js/paypal.js"></script>
<script src="https://js.braintreegateway.com/web/3.29.0/js/paypal-checkout.js"></script>
<script src="https://js.braintreegateway.com/web/3.29.0/js/three-d-secure.js"></script>
<script>
$(function () {
var client_token = '@ViewBag.ClientToken';
var paypalButton = document.querySelector('#paypal-button');
var cardButton = document.querySelector('#card-button');
braintree.client.create({
authorization: client_token
}, function (clientErr, clientInstance) { //****
if (clientErr) {
//console.error('Error creating client:', clientErr);
return;
}
//paypal支付
braintree.paypal.create({
client: clientInstance //****
}, function (paypalErr, paypalInstance) {
if (paypalErr) {
console.error('Error creating PayPal:', paypalErr);
return;
}
paypalButton.removeAttribute('disabled');
paypalButton.addEventListener('click', function (event) {
// Because tokenization opens a popup, this has to be called as a result of
// customer action, like clicking a button. You cannot call this at any time.
paypalInstance.tokenize({
flow: 'checkout',
amount: document.querySelector('#amount').value,
currency: 'USD'
// For more tokenization options, see the full PayPal tokenization documentation
// http://braintree.github.io/braintree-web/current/PayPal.html#tokenize
}, function (tokenizeErr, payload) {
if (tokenizeErr) {
if (tokenizeErr.type !== 'CUSTOMER') {
console.log('Error tokenizing:', tokenizeErr);
}
return;
}
// Tokenization succeeded
document.querySelector('#nonce').value = payload.nonce;
$("#payer").html(payload.details.email);
paypalButton.firstChild.innerHTML = "switch account";
console.log('Paypal Got nonce:', payload.nonce);
});
}, false);
});
///信用卡支付
// Create input fields and add text styles
braintree.hostedFields.create({
client: clientInstance, //****
// Add information for individual fields
fields: {
number: {
selector: '#cc-number',
placeholder: '1111 1111 1111 1111'
},
cvv: {
selector: '#cc-cvv',
placeholder: '123'
},
expirationDate: {
selector: '#cc-expiration-date',
placeholder: '10 / 2019'
}
}
}, function (err, hostedFieldsInstance) {
if (err) {
console.log(err);
return;
}
hostedFieldsInstance.on('cardTypeChange', function (event) {
// Change card bg depending on card type
if (event.cards.length === 1) {
//$(form).removeClass().addClass(event.cards[0].type);
$('#card-image').removeClass().addClass(event.cards[0].type);
//$('header').addClass('header-slide');
// Change the CVV length for AmericanExpress cards
if (event.cards[0].code.size === 4) {
hostedFieldsInstance.setAttribute({
field: 'cvv',
attribute: 'placeholder',
value: '1234'
});
}
} else {
hostedFieldsInstance.setAttribute({
field: 'cvv',
attribute: 'placeholder',
value: '123'
});
}
});
cardButton.addEventListener('click', function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (err, payload) {
if (err) {
console.log(err);
return;
}
var a = payload.details.cardType;
var b = payload.details.lastFour;
//document.querySelector('#nonce').value = payload.nonce;
// This is where you would submit payload.nonce to your server
var my3DSContainer;
braintree.threeDSecure.create({
client: clientInstance
}, function (threeDSecureErr, threeDSecure) {
if (threeDSecureErr) {
console.log("Error creating 3DSecure" + threeDSecureErr);
return;
}
else{
threeDSecure.verifyCard({
nonce: payload.nonce,
amount: document.querySelector('#amount').value,
addFrame: function (err, iframe) {
// Set up your UI and add the iframe.
my3DSContainer = document.createElement('div');
my3DSContainer.appendChild(iframe);
document.body.appendChild(my3DSContainer);
},
removeFrame: function () {
//Remove UI that you added in addFrame.
document.body.removeChild(my3DSContainer);
}
}, function (err, thpayload) {
if (err) {
console.log(err);
return;
}
//hostedFieldsInstance.clear('number');
//hostedFieldsInstance.clear('cvv');
//hostedFieldsInstance.clear('expirationDate');
debugger;
if (thpayload.liabilityShiftPossible) {
if (thpayload.liabilityShifted) {
//Liablity has shifted
//submitNonceToServer(payload.nonce);
document.querySelector('#nonce').value = thpayload.nonce;
console.log('Card Got nonce:', thpayload.nonce);
} else {
console.log("Invalid Card!");
}
} else {
document.querySelector('#nonce').value = thpayload.nonce;
console.log('No3D nonce:', thpayload.nonce);
}
});
}
});
});
}, false);
});
});
});
</script>
界面效果:
paypal和信用卡的初始化方法是不一樣的,信用卡的稍微復(fù)雜點(diǎn)。它們所依賴的js也是不一樣的。
這里要注意,所有引入的braintree官方的js的版本必須要一致,原因嘛,你去改下版本試下就知道了。版本不一致的話,paypal支付或者信用卡支付的時(shí)候官方會(huì)返回錯(cuò)誤給我們,提示就是必須引入的client.min.js版本和paypal-checkout.js或者其他的js要一致。你用到哪種支付的時(shí)候,就會(huì)提示你要與哪種支付所依賴的js版本要一致。
client.min.js
這是第一個(gè)要引入的,客戶端支付控件初始化,其他支付方式的初始化都是依賴于braintree.client.create()返回的clientInstance作為參數(shù)去初始化的。代碼中注釋了*的地方。
2. hosted-fields.min.js
這是將信用卡支付中的輸入框控件(卡號(hào),CVV等)標(biāo)記為信用卡支付時(shí)校驗(yàn)的字段,標(biāo)記了之后我們就拿不到其客戶真正輸入的值,且一切相應(yīng)的判斷(比如卡號(hào),CVV的正確性,必填性)這些就都不需要我們自己來控制。其外最重要的,不可讓商城拿到客戶的卡信息這是為了保護(hù)客戶的財(cái)產(chǎn)泄露,引發(fā)商家的承擔(dān)不必要的責(zé)任。入正式的時(shí)候需要進(jìn)行PCI安全驗(yàn)證,這點(diǎn)上就很能讓你通過了。
3. paypal-checkout.js
這是paypal支付需要的,braintree.paypal.create()。這個(gè)很簡(jiǎn)單的。
4.three-d-secure.js
3D安全校驗(yàn)需要的,這個(gè)東西啟用的主要原因就是 為支付減少風(fēng)險(xiǎn)。也為商家轉(zhuǎn)移責(zé)任。
參考資料:
https://developers.braintreepayments.com/guides/hosted-fields/examples/javascript/v3