I'm attempting to use Stripe as a payment method, on an ASP.Net MVC project
We've gone the route of using stripe elements to define our own look and feel for the card details.
I've followed the tutorials, and have managed to get the card widgit displaying nicely.
Where it fails is on the submission.
I've hooked up the following JS to the button (taken straight from the guides)
var form = document.getElementById('payment-form');
var clientSecret = $("#authcode").val();
form.addEventListener('submit', function(ev) {
ev.preventDefault();
stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: card,
billing_details: {
name: 'Jenny Rosen'
}
}
}).then(function(result) {
if (result.error) {
// Show error to your customer (e.g., insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
}
}
});
});
Now when I put a breakpoint on it does enter the stripe.confirmCardPayment function
However I never get a response. I've put a break point on the line if (result.error) { but it never fires. I've sat and left it for over two minutes.
No errors in the chrome console, and also no network traffic.
I am happy that the JS is all loaded correctly because if I hit submit again the Stripe JS lib correctly tells me I have an in-flight confirmCardPayment
Any suggestions are most appreciated.
Looks you are using jQuery at:
var clientSecret = $("#authcode").val();
You should wrap js with
$(document).ready(function(){
....
}):
Right, I've finally got it working.
Yes I believe with the answers given by Nolan / Raphael that it was indeed a caching issue!
However. Deleting the cache with CTRL+SHIFT+DEL had no effect.
Only way I could get the cache to clear was to physically alter the JS.
Thanks again to Nolan / Raphael for their suggestions :)
Related
Hi we are trying to integrate Apple Pay on a website using the payment provider Pay360.
Pay360 have provided us with the domain-verification file and we have uploaded it to the merchant domain -
https://example.com/.well-known/apple-developer-merchantid-domain-association
When we try to checkout we get this message in the dev console -
"Unsupported Apple Pay validation domain"
This is the Pay360 integration docs:
https://docs.pay360.com/alternative-payments/getting-started-with-apple-pay/
I've included the code used at the checkout that creates the Apple Pay session but it's not triggering the 'session.onvalidatemerchant' function because of that I can't get 'validationURL' from that event.
Here's the code -
jQuery(document).on('click','#applePay',function() {
var paymentRequest = {
countryCode: 'GB',
currencyCode: 'GBP',
supportedNetworks: ['visa', 'masterCard', 'amex', 'discover'],
merchantCapabilities: [ 'supports3DS' ],
total: { label: 'Online Store', amount: '0.05' },
};
var session = new ApplePaySession(3, paymentRequest);
session.onvalidatemerchant = function (event) {
console.log(event);
var url = event.validationURL;
alert(url);
}
session.onpaymentauthorized = function (event) {
console.log(event);
}
session.oncancel = function(event) {
console.log(event);
}
session.begin();
});
We asked Pay360 Support for help but they asked us to contact Apple for help. Here is what Pay360 said -
Unfortunately at this point Pay360 cannot support you anymore as it is not a problem at our end.
The issue is between the yourself and ApplePay especially as you are going down the API path. Therefore, if you are still encountering further issues after the previous advice has been taken, you should in the first instance review ApplePay's integration documentation or contact ApplePay.
Previous advice -
From the code snippet given, the merchant is calling begin() before they've finished initialising the ApplePaySession object - it makes sense that it wouldn't trigger the onvalidatemerchant event if there wasn't one set at that point.
The merchant should bind onvalidatemerchant and onpaymentauthorized (and anything else they want to bind on the session) before calling the begin() function.
This should enable the merchant to continue debugging the problem.
Please can someone advise how to fix?
I have MVC project and facing one issue with stripe flow. any help would be really appreciated.
Below is my flow.
I'm creating card token from UI using stripe js version v3. with this code, I'm able to retrieve both card and token perfectly from stripe.
stripe.createToken(card, { name: name }).then(function (result) {
if (result.error) {
// Inform the customer that there was an error.
} else {
// stripeTokenHandler will post the form to back end with token, here we are getting card with proper name,
// but we are just sending token to back end
stripeTokenHandler(result.token);
}
});
Then I use that token further to create a stripe source with C# back end code, for that I have used Stripe.net, Version=37.15.0.0m below is the code.
// creating a stripe customer, consider this is working fine
Stripe.Customer customer = GetCustomerService().Create(options, requestOptions);
// create the credit card source and attach it to the current StripeCustomerId
var options = new Stripe.SourceCreateOptions()
{
Type = "card",
Token = token,
};
var requestOptions = new Stripe.RequestOptions();
if (stripeAccountId.IsNotEmpty())
requestOptions.StripeAccount = stripeAccountId;
Stripe.Source source = null;
try
{
source = GetSourceService().Create(options, requestOptions);
}
catch (StripeException ex)
{
msgs.Add(ex.Message, MessageType.UserError, ex);
msgs.Add($"Payment source was not created", MessageType.UserError);
}
And this is how I'm retrieving stripe sources.
List<Stripe.Source>() sources = GetSourceService().List(customerId).ToList();
This all works fine, but the retrieved sources does not contains the name of card holder, which was there when we created and retrieved token. I tried to look at the documentation, but no luck.
I think it's issue in the flow, I might be missing some pieces but not sure what it is. Again, any help would be really appreciated. Thanks!
If you're building a net new project you should really look at using the newer Payment Methods / Payment Intents APIs instead of what you're doing here.
That said, you don't seem to be attaching the Token to the Customer, rather you seem to be creating a Source - which is different. If you do want to create the Source with a name, you'd want to provide that.
We're currently struggling with Braintree PayPal payment in combination with regular bank transfer via IBAN. Basically, we present two subscription options to the visitor: PayPal (via Braintree) and IBAN transaction.
The PayPal method works fine but when we don't select PayPal but IBAN bank transfer, we're getting the following console error:
We understand that this is the correct behaviour since the PayPal fields are not filled, but how is it possible to have PayPal as an optional payment method without throwing an error when the fields are not filled?
We're using the basic js implemetion via DropUI.
<div class="bt-drop-in-wrapper" id="showpaypalfields">
<div id="bt-dropin" class="paypaldiv"></div>
</div>
<script src="https://js.braintreegateway.com/js/braintree-2.27.0.min.js"></script>
<script>
var client_token = "123TOKEN";
braintree.setup(client_token, "dropin", {
container: "bt-dropin"
});
</script>
UPDATE:
Both forms are visible on the page instantly, they are not loaded afterwards via Ajax or any kind. So, the PayPal option via Braintree should only validate if for example a checkbox is set. For example, the checkbox given in the screenshot below (toggles visibility of both fieldsets).
UPDATE #2:
For anyone interested in the final solution:
var btInstance;
$('input#paymentmethod-1').change(function(){
if ( $(this).is(':checked') == true ) {
teardown();
}
});
$('input#paymentmethod-2').change(function(){
if ( $(this).is(':checked') == true ) {
setup();
}
});
function setup() {
if (btInstance) {
return;
} else {
var client_token = "<ps:braintreetoken />";
braintree.setup(client_token, "dropin", {
container: "bt-dropin",
onReady: function (bt) {
btInstance = bt;
}
});
}
}
function teardown() {
if (!btInstance) {
return;
}
btInstance.teardown(function () {
btInstance = null;
});
}
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
Drop-in UI is still loaded when you select the Lastschrift payment option, which is why you're receiving the validation errors.
One way to avoid these validation errors is to use the 'teardown' method in the 'onReady' callback in braintree.js to remove the Drop-in UI if a customer selects Lastschrift.
Alternatively, you can separate each of these payment methods into entirely different form elements on your page.
I'm using Firebase perhaps slightly unconventionally -for simple form submission. Submission of my website's contact form simply results in:
ref.push({name:'dr foo', email:'1#2.com', message:'bar'}, myCallback);
The Firebase is hooked up to Zapier to send the site owner an email. All works well, but I'd like to be able to handle the user loosing their connection. When Firebase can't reach the server I'd like to display: "Please check your connection", or a similar message when the user hits the send button. The "Thanks, we'll be in touch"-type message should only be displayed on a successful write.
At first I tried including an if (error) branch in the callback, but of course disconnection is not something that Firebase considers an error as it "catches up" when it can.
I also tried the code in the docs which monitors .info/connected. While this wouldn't display a message on a form submission attempt, I was thinking I could instead display a warning if disconnected. The sample worked intermittently (Chrome 39, Firefox 30, Linux Mint), but the lag between disconnection and the event firing means it's probably not suitable for this case.
Is what I'm trying to do possible?
It indeed seems that the .info/connected values only changes once some other data transfer occurs (and fails).
The only way I can come up with is by using the transaction mechanism with applyLocally set to false. E.g.
function testOnlineStatus() {
var ref = new Firebase('https://your.firebaseio.com/');
ref.child('globalcounter').transaction(function(count) {
return (count || 0) + 1;
}, function(error, committed, snapshot) {
if (error) {
alert('Are you offline?');
}
}, false /* force roundtrip to server */);
}
setInterval(testOnlineStatus, 2000);
This one triggered for me after about 15 seconds.
I am using Paypals Adaptive Payments and Embedded flow feature to provide checkout via a minibrowser. Everything seems to be working correctly in the sandbox environment except that when the payment is completed successfully, the user is never redirected to my returnUrl set in the PAY API request. Same goes for my cancelUrl.
After the payment is complete, the user is shown an order overview in the minibrowser and a button labelled "close". If a user clicks this button, the minibrowser is closed.
If a user clicks cancel at any time, the minibrowser is closed.
There doesn't seem to be a way to have my page aware of the change besides setting up some polling or something which doesn't make sense, my returnUrl and cancelUrl should be used somewhere, right?
this is my code to get the redirect url (using adaptive payments gem):
pay_request = PaypalAdaptive::Request.new
data = {
'requestEnvelope' => {'errorLanguage' => 'en_US'},
'currencyCode' => 'USD',
'receiverList' =>
{ 'receiver' => [
{'email' => '...', 'amount'=> 10.00}
]},
'actionType' => 'PAY',
'returnUrl' => 'http://www.example.com/paid',
'cancelUrl' => 'http://www.example.com/cancelled',
'ipnNotificationUrl' => 'http://www.example.com/ipn'
}
pay_response = pay_request.pay(data)
redirect_to pay_response.approve_paypal_payment_url "mini"
And here is how I am setting up the paypal js:
var dg = new PAYPAL.apps.DGFlowMini({ trigger: "buyit", expType: "mini" });
It all seems pretty straight forward, not sure what I am missing.
Well - seems to be a bug on our side - just tried it myself and confirmed with our integration teams. :-(
Unfortunately the other short term fix I can think of other than what you've mentioned (checking for the existence of the popup window) is to call the PaymentDetails API from your server side to check the status of the Payment. I've opened the bug on our side but don't have an ETA.
Edit 10/18: Sorry I'm wrong. This is working - it's just that our developer guide is not providing all the required information. In case of the mini-browser flow, you would need to provide a 'callbackFunction' and also name your dgFlow variable as 'dgFlowMini'. (the latter is important - as apdg.js is expecting the 'dgFlowMini' variable to be defined) Here is the code that works:
var returnFromPayPal = function(){
alert("Returned from PayPal");
// Here you would need to pass on the payKey to your server side handle to call the PaymentDetails API to make sure Payment has been successful or not
// based on the payment status- redirect to your success or cancel/failed urls
}
var dgFlowMini = new PAYPAL.apps.DGFlowMini({trigger: 'em_authz_button', expType: 'mini', callbackFunction: 'returnFromPayPal'});
I have a working sample here: https://pp-ap-sample.appspot.com/adaptivesample?action=pay (make sure you select mini as the Experience Type)
We will get our docs updated and also cleanup apdg.js to remove the dependency on the JS variable name.
Looks like the PayPal experience for embedded flows has gotten worse. Now you'll receive an error message after invoking mini or lightbox that says "Payment can't be completed. This feature is currently unavailable."