example/sinatra/index.erb in veritrans-2.3.0 vs example/sinatra/index.erb in veritrans-2.4.0

- old
+ new

@@ -1,214 +1,202 @@ <!doctype html> <html> <head> - <title>veritrans-ruby demo</title> - <link rel="icon" type="image/x-icon" href="https://account.midtrans.com/favicon.ico" /> - <link rel="stylesheet" href="/style.css"> + <title>Midtrans-Ruby simple demo</title> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/featherlight/1.7.12/featherlight.min.css"> </head> <body> <header> - <h3>Midtrans sinatra app</h3> + <h3>Midtrans sample demo sinatra app</h3> <a href="https://github.com/veritrans/veritrans-ruby" class="github">Source Code</a> </header> <section> - <h4>VT-Web</h4> - <form action="/charge_vtweb" method="GET" id="vtweb_form"> - <fieldset> - <p> - <label>Language</label> - <select name="locale"> - <option></option> - <option value="id">Indonesian</option> - <option value="en">English</option> - </select> - </p> + <h4>Snap Popup</h4> + <a href="/snap">Click here</a> +</section> - <div class="form-row"> - <label>Payment Types</label> - <ul> - <% @payment_types = %w{CREDIT_CARD MANDIRI_CLICKPAY MANDIRI_BILL CIMB_CLICKS INDOMARET BANK_TRANSFER MANDIRI_BILL} %> - <% for type in @payment_types %> - <li> - <label> - <input type="checkbox" name="enabled_payments[]" value="<%= type %>"> - <%= type.split("_").map(&:capitalize).join(' ') %> - </label> - </li> - <% end %> - </ul> - <br/> - <small class="types-hint">By default Veritrans will show all available types</small> - </div> +<section> + <h4>Snap Redirect</h4> + <a href="/snap_redirect">Click here</a> +</section> +<br> +<h3>Core API Credit Card</h3> +<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/picomodal/3.0.0/picoModal.js"></script> - <p> - <label>Credit Card BIN promo</label> - <input type="text" name="bin_promo" placeholder="411111, 500000, bni, mandiri, 3111"> - <br/> - <small class="bins-hint"> - <a href="https://api-docs.midtrans.com/#card-features-bin-promo">See documentation</a> - </small> - </p> - - <p> - <label>Credit Card 3D Secure</label> - <select name="credit_card_3d_secure"> - <option></option> - <option value="true">Yes</option> - <option value="false">No</option> - </select> - </p> - - <div class="form-row"> - <label>Credit Card Installment</label> - <ul> - <li> - <label><input type="checkbox" name="installment[bni]">BNI</label> - </li> - <li> - <label><input type="checkbox" name="installment[mandiri]">Mandiri</label> - </li> - <li> - <label><input type="checkbox" name="installment[bca]">BCA</label> - </li> - </ul> - </div> - - </fieldset> - +<h1>Checkout</h1> +<form action="/coreapi_card_charge_ajax_handler" method="POST" id="payment-form"> + <fieldset> + <legend>Checkout</legend> + <small><strong>Field that may be presented to customer:</strong></small> <p> - <input type="submit" value="Create payment page"> + <label>Card Number</label> + <input class="card-number" value="4811 1111 1111 1114" size="23" type="text" autocomplete="off" /> + </p> <p> - </form> -</section> + <label>Expiration (MM/YYYY)</label> + <input class="card-expiry-month" value="12" placeholder="MM" size="2" type="text" /> + <span> / </span> + <input class="card-expiry-year" value="2025" placeholder="YYYY" size="4" type="text" /> + </p> + <p> + <label>CVV</label> + <input class="card-cvv" value="123" size="4" type="password" autocomplete="off" /> + </p> -<section> - <h4>VT-Direct</h4> + <small><strong>Fields that shouldn't be presented to the customer:</strong></small> + <p> + <label>3D Secure</label> + <input class="authenticate_3ds" type="checkbox" name="authenticate_3ds" value="true" checked> + </p> - <form action="/charge_vtdirect" method="post" id="card_form"> - <input type="hidden" name="token_id" id="card_token"> - <fieldset> - <legend>Credit card</legend> - <p> - <label for="gross_amount">Amount, Rp.</label> - <input type="text" name="gross_amount" id="gross_amount" value="30000"> - </p> - <p> - <label for="card_number">Card number</label> - <input type="text" id="card_number" style="width: 150px" value="4811 1111 1111 1114"> - <br> - <small style="margin-left: 100px" class="card-numbers"> - <a onclick="$('#card_number').val('4811 1111 1111 1114')">success Visa</a> - <a onclick="$('#card_number').val('5810 1111 1111 1112')">success MasterCard</a> - <a onclick="$('#card_number').val('4511 1111 1111 1117')">challenge</a> - <a onclick="$('#card_number').val('4611 1111 1111 1116')">Deny by FDS</a> - <a onclick="$('#card_number').val('4911 1111 1111 1113')">Deny by bank</a> - <a href="https://docs.midtrans.com/en/reference/test.html" target="_blank">documentation</a> - </small> - </p> - <p> - <label for="card_cvc">Security Code</label> - <input type="text" id="card_cvc" style="width: 30px" placeholder="cvc" value="123"> - </p> - <p> - <label for="card_exp">Expiration date</label> - <input type="text" id="card_exp" placeholder="MM / YY" value="12 / 18"> - </p> + <input id="token_id" name="token_id" type="hidden" /> + <button class="submit-button" type="submit">Submit Payment</button> + </fieldset> +</form> - <p> - <label for="card_secure">3D-secure</label> - <input type="checkbox" id="card_secure"> - </p> +<code> + <b>Transaction Result:</b> + <pre id="result"> Awaiting transactions... </pre> + <b>Transaction verified status result:</b> + <pre id="status-result"> Awaiting transactions... </pre> + <pre> + <b>Testing cards:</b> - </fieldset> + <b>For 3D Secure:</b> + Visa success 4811 1111 1111 1114 + Visa deny by bank 4711 1111 1111 1115 + Visa deny by FDS 4611 1111 1111 1116 - <input id="submit_btn" type="submit"> - </form> -</section> + MasterCard success 5211 1111 1111 1117 + MasterCard deny by bank 5111 1111 1111 1118 + MasterCard deny by FDS 5411 1111 1111 1115 -<section> - <h4>Localization</h4> - Indonesian translation for validation messages - <a href="/localization">Click here</a> -</section> + Challenge by FDS 4511 1111 1111 1117 + </pre> +</code> -<section> - <h4>Recurring</h4> - <a href="/recurring">Click here</a> -</section> +<!-- Import MidtransNew3ds library --> +<!-- TODO change data-environment to `production` for Production mode --> +<!-- TODO change data-client-key to your production client key for Production mode --> +<script id= "midtrans-script" src="https://api.midtrans.com/v2/assets/js/midtrans-new-3ds.min.js" data-environment="sandbox" data-client-key=<%= Midtrans.config.client_key %> type="text/javascript"></script> -<section> - <h4>Credit Card Points</h4> - <a href="/points">Click here</a> -</section> +<!-- Javascript for token generation --> +<script type="text/javascript"> + // On Submit button clicked + document.querySelector(".submit-button").onclick = function (event) { + console.log("SUBMIT button clicked"); + // prepare cardData + var cardData = { + "card_number": document.querySelector(".card-number").value, + "card_exp_month": document.querySelector(".card-expiry-month").value, + "card_exp_year": document.querySelector(".card-expiry-year").value, + "card_cvv": document.querySelector(".card-cvv").value, + }; + // [1] Use card data to get card token on the callback + MidtransNew3ds.getCardToken(cardData, getCardTokenCallback); -<section> - <h4>Snap</h4> - <a href="/widget">Click here</a> -</section> + event.preventDefault(); return false; + }; -<script src="https://api.sandbox.midtrans.com/v2/assets/veritrans.js"></script> -<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> -<script src="//cdnjs.cloudflare.com/ajax/libs/jquery.payment/1.0.2/jquery.payment.js"></script> -<script src="//cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/0.9.9/jquery.magnific-popup.min.js"></script> -<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/0.9.9/magnific-popup.css"> + // getCardTokenCallback triggered when `MidtransNew3ds.getCardToken` completed. + var getCardTokenCallback = { + onSuccess: function(response){ + // success to get card token + // [2] Send AJAX to let backend charge the card using the card token_id + fetch("/coreapi_card_charge_ajax_handler", { + method : "POST", + body: JSON.stringify({ + "token_id" : response.token_id, + "authenticate_3ds" : document.querySelector('.authenticate_3ds').checked + }), + headers: {'Content-Type': 'application/json'}, + }) + .then(function(response) { return response.json(); }) + .then(function(responseObj) { + console.log("Charge response:",responseObj); + if (responseObj.status_code == "201"){ + // [3.1] Transaction need 3DS authentication + MidtransNew3ds.authenticate(responseObj.redirect_url, callback3dsAuthentication); + } else { + // Transaction do not need 3DS Authentication, transaction is complete with result + transactionComplete(responseObj); + } + }) + }, + onFailure: function(response){ + // fail to get card token + transactionComplete(response); + } + } -<script type="text/javascript"> - // set Veritrans settings - Veritrans.url = "<%= Veritrans.config.api_host %>/v2/token"; - Veritrans.client_key = "<%= Veritrans.config.client_key %>"; + var callback3dsAuthentication = { + performAuthentication: function(redirect_url){ + // [3.2] 3ds authentication redirect_url received, open iframe to display to customer + popupModal.openPopup(redirect_url); + }, + // [3.3] When 3DS authentication result received, which contains transaction result + // it will trigger one of function below, according to status: success/failure/pending + onSuccess: function(response){ + transactionComplete(response); + }, + onFailure: function(response){ + transactionComplete(response); + }, + onPending: function(response){ + transactionComplete(response); - function createTokenData() { - return { - // Optional params: - // secure: true - // bank: 'MANDIRI' + } + } - card_number: $('#card_number').val(), - card_cvv: $('#card_cvc').val(), - card_exp_month: $('#card_exp').val().match(/(\d+) \//)[1], - card_exp_year: '20' + $('#card_exp').val().match(/\/ (\d+)/)[1], - gross_amount: $('#gross_amount').val(), - secure: $('#card_secure')[0].checked - }; - } + function transactionComplete(responseObj){ + // Close 3DS popup, then display the result (for example) + console.log("transactionComplete with status: ",responseObj); + popupModal.closePopup(); - $(document).ready(function () { - $('#card_number').payment('formatCardNumber'); - $('#card_cvc').payment('formatCardCVC'); - $('#card_exp').payment('formatCardExpiry'); + document.querySelector("#result").innerText = JSON.stringify(responseObj, null, 2); + document.querySelector("#result").scrollIntoView(); - $('#card_form').on('submit', function (event) { - var form = this; - $('#submit_btn').attr('disabled', true).val("Processing ..."); - event.preventDefault(); + if (responseObj.transaction_id){ + // [4] Inform the result to backend update DB status and verify to Midtrans + fetch('/check_transaction_status', { + method : "POST", + body: JSON.stringify({ "transaction_id" : responseObj.transaction_id }), + headers: {'Content-Type': 'application/json'}, + }) + .then(function(statusResponse) { return statusResponse.json(); } ) + .then(function(statusResponseObj) { + // Transaction status received after being verified + console.log("Check transaction response:",statusResponseObj); + // transactionComplete(statusResponseObj); + document.querySelector("#status-result").innerText = + JSON.stringify(statusResponseObj, null, 2); - Veritrans.token(createTokenData, function (data) { - console.log('Token data:', data); - // if we get url then it's 3d-secure transaction - // so we need to open that page - // this callback function will be called again after user confirm 3d-secure - // you can also redirect on server side - if (data.redirect_url) { - $.magnificPopup.open({ - items: { type: 'iframe', src: data.redirect_url } - }); - $.magnificPopup.instance.content.find('iframe').height(590); - // if no redirect_url and we have token_id then just make charge request - } else if (data.token_id) { - $('#card_token').val(data.token_id); - $.magnificPopup.close(); - form.submit(); - // if no redirect_url and no token_id, then it should be error - } else { - alert(data.validation_messages ? data.validation_messages.join("\n") : data.status_message); - $('#submit_btn').removeAttr('disabled').removeAttr("value"); + }) } - }); - }); - }); + } + + // helper functions below + let popupModal = (function(){ + let modal = null; + return { + openPopup(url){ + modal = picoModal({ + content:'<iframe frameborder="0" style="height:90vh; width:100%;" src="'+url+'"></iframe>', + width: "75%", + closeButton: false, + overlayClose: false, + escCloses: false + }).show(); + }, + closePopup(){ + try{ + modal.close(); + } catch(e) {} + } + } + }()); </script> </body> -</html> +</html> \ No newline at end of file