Stripe subscriptions: how to pass customer's name and email to PaymentIntent? - javascript

To set up subscriptions, I am following step-by-step the instructions at https://stripe.com/docs/payments/save-after-payment
All is good until step 5 (Save the card): I want to save the customer's name and email there, and stripe.confirmCardPayment doesn't seem to accept it (unlike the sample as https://github.com/stripe-samples/payment-form-modal/blob/master/cards-only/client/elementsModal.js)
Even when passing such data, the Dashboard shows the customer doesn't have name and email.
stripe.confirmCardPayment(paymentIntent.client_secret, {
payment_method: {
card: card,
billing_details: { name: content.customerName } // << WHAT I WANT
}
})
.then(function(result) {
if (result.error) {
var displayError = document.getElementById("card-errors");
displayError.textContent = result.error.message;
} else {
stripePaymentHandler();
}
});
How to pass the customer's name and email with stripe.confirmCardPayment?

Related

Stripe payment failing after trial period

I'm attempting to create a monthly subscription with free 7 day trial, but after the trial period the payment fails.
EDIT: It appears to fail because the customer has no default payment method, so despite the payment method being attached to customer, it is not set to default. I can not figure out how to set it to default payment method.
I am setting ConfirmCardSetup in frontend javascript, which I believe is tying the card to the customer. And I am creating the customer, and starting the subscription/trial in my backend django view.
I have found this in Stripe documentation:
"To use this PaymentMethod as the default for invoice or subscription
payments, set invoice_settings.default_payment_method, on the Customer
to the PaymentMethod’s ID."
but I am unsure how to get the Payment Method ID from front end, and use it to update the customer.
Here is my subscription create view:
class SubscriptionCreateView(View, SubscriptionCancellationMixin,
CustomerMixin, StripeReferenceMixin, FetchCouponMixin):
"""View to Create subscription and sync with stripe"""
def post(self, request, *args, **kwargs):
context = {}
subscription_payload = {}
price_id = request.POST.get('price_id')
coupon_id = request.POST.get('coupon_id')
customer = self.fetch_customer(request.user)
#Retrieve stripe coupon id or None
if coupon_id != '':
stripe_coupon_id, is_valid = self.is_coupon_valid(coupon_id)
#Set payload to create a subscription
subscription_payload['coupon'] = stripe_coupon_id
#Send invalid coupon response
if not is_valid:
context['invalid_coupon'] = True
response = JsonResponse(context)
response.status_code = 400
return response
if not customer:
customer = self.stripe.Customer.create(
email=request.user.email
)
try:
now = int(time.time())
# Cancel the previous subscription.
self.cancel_subscription(customer)
#Create a new subscription
subscription_payload.update({
'customer':customer.id,
'items': [{
'price': price_id,
},
],
'trial_end': now +30,
},
)
#create a setup intent
setup_intent = self.stripe.SetupIntent.create(
payment_method_types=["card"],
customer=customer.id,
)
subscription = self.stripe.Subscription.create(**subscription_payload)
# Sync the Stripe API return data to the database,
# this way we don't need to wait for a webhook-triggered sync
Subscription.sync_from_stripe_data(subscription)
request.session['created_subscription_id'] = subscription.get('id')
# Note we're sending the Subscription's
# latest invoice and client secret
# to the front end to confirm the payment
context['subscriptionId'] = subscription.id
context['clientSecret'] = setup_intent['client_secret']
except Exception as e:
response = JsonResponse({})
response.status_code = 400
return response
return JsonResponse(context)
And here's the relevant javascript!
var stripe = Stripe($('#public-key').val());
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
}
};
var card = elements.create("card", { style: style });
card.mount("#card-element");
//Capture modal payment button click
$(document).on('click', '#submit-payment-btn', function (e) {
e.preventDefault();
//Send an ajax call to backend to create a subscription
$(this).prop('disabled', true);
let spinnerHtml = '<div class="spinner-border text-light"></div>';
let origButtonHtml = $(this).html();
$(this).html(spinnerHtml);
$.ajax({
url: $(this).data('create-sub-url'),
type: 'POST',
data: {
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val(),
'price_id': $(this).data('price-id'),
'coupon_id': $("#coupon_id").val()
},
success: function (result) {
if(!result.clientSecret)
{
console.log("result not okay")
window.location.href = '/'
}
else{
$('#client-secret').val(result.clientSecret);
// Confirm payment intent.
console.log('set up confirmed');
stripe.confirmCardSetup(result.clientSecret, {
payment_method: {
card: card,
billing_details: {
name: $('#cardholder-name').val(),
},
}
}).then((result) => {
if (result.error) {
alert('Payment failed:'. result.error.message);
} else {
window.location.href = '/'
}
});
}
},
error: function (result){
$('#submit-payment-btn').html(origButtonHtml);
if(result.responseJSON.invalid_coupon)
{
if($(".coupon-error").length == 0)
$('.coupon-div').append('<p class="coupon-error text-center" style="color:red">Invalid coupon code</p>')
}
else{
$('#payment-modal').modal('hide');
alert('Something Went Wrong!')
}
}
}
);
})
Thanks for any help or point in the right direction! I've been trying to solve this for hours!

stripe - can not use same payment-method for new paymentIntents

I have the issue that saved 3d-secure cards can not be re-used again.
it says, card number invalid. below is the paymentmethod created. (sorry, it is in german).
in this picture, you see, it says "For future usage" and shows the paymentintent id.
if I want to use the saved card for new payment this way:
it says, card is invalid.
I have some more codes, so dont know which part is relevant. i will paste js part already here:
stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: card,
billing_details: {},
},
return_url: 'https://localhost:8000/'
}).then(function(data) {
console.log(data);
if (data.error) {
showError(data.error.message);
} else if (data.paymentIntent.status === "succeeded") {
orderComplete(clientSecret);
}
});

Stripe client intergration not taking affect after I click buy now link

I followed this documentation and my stripe checkout is not working. I have taken out the sku and pk from the SO snippet below but can anybody see what I have done wrong as I thought I implemented it correctly.
When I click the buy now link, nothing happens, don't even redirect to the checkout page.
HTML link:
<a class="buy-btn">Buy Now</a>
...
Javascript:
<script>
(function () {
var stripe = Stripe('pk_test_xxx');
var checkoutButton = document.getElementsByClassName('buy-btn');
checkoutButton.addEventListener('click', function () {
// When the customer clicks on the button, redirect
// them to Checkout.
stripe.redirectToCheckout({
items: [{ sku: 'sku_xxx', quantity: 1 }],
// Do not rely on the redirect to the successUrl for fulfilling
// purchases, customers may not always reach the success_url after
// a successful payment.
// Instead use one of the strategies described in
// https://stripe.com/docs/payments/checkout/fulfillment
successUrl: window.location.protocol + '//www.xxx-online.com/xxx-leap/success',
cancelUrl: window.location.protocol + '//www.xxx-online.com/xxx-leap/cancelled',
})
.then(function (result) {
if (result.error) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer.
var displayError = document.getElementById('error-message');
displayError.textContent = result.error.message;
}
});
});
})();

TypeError: balance.toNumber is not a function

can someone please take a look on where the problem is? i'm all out of ideas.
this is a test driven code from a tutorial i am following.
it('ends token sale', function() {
return DappToken.deployed().then(function(instance) {
// Grab token instance first
tokenInstance = instance;
return DappTokenSale.deployed();
}).then(function(instance) {
// Then grab token sale instance
tokenSaleInstance = instance;
// Try to end sale from account other than the admin
return tokenSaleInstance.endSale({
from: buyer
});
}).then(assert.fail).catch(function(error) {
assert(error.message.indexOf('revert' >= 0, 'must be admin to end sale'));
// End sale as admin
return tokenSaleInstance.endSale({
from: admin
});
}).then(function(receipt) {
return tokenInstance.balanceOf(admin);
}).then(function(balance) {
assert.equal(balance.toNumber(), 999990, 'returns all unsold dapp tokens to admin');
// Check that the contract has no balance
balance = web3.eth.getBalance(tokenSaleInstance.address);
assert.equal(balance.toNumber(), 0);
});
});
this is the error log:
TypeError: balance.toNumber is not a function
at test\DappTokenSale.js:127:28
at process._tickCallback (internal/process/next_tick.js:68:7)
i've tried selfdestruct() but i cant find fixes from any sites, so instead, i just transfer the remaining tokens to the admin. but then, i keep running into this problem. here's the contract for more reference:
function endSale() public {
//require admin(only)
require(msg.sender == admin);
//transfer remaining dapp tokens to admin
require(tokenContract.transfer(admin, tokenContract.balanceOf(address(this))));
admin.transfer(address(this).balance);
}

Get parameters and store and use them on variables to use on my method

I want to get some parameters and use them to reset password function from firebase.
This is how my link looks like:
http://localhost:8080/passwordreset?mode=resetPassword&oobCode=y6FIOAtRUKYf88Rt5OlEwxUuTyEmb3M4gquZSIseX2UAAAFevpj-gw&apiKey=AIzaSyBaCCvq-ZEfQmdrL7fmElXDjZF_J-tku2I
I want to get mode, oobCode and apiKey.
Here is what I have for now:
export default {
data: function() {
return {
passwordNew: '',
passwordConfirm: '',
mode:'',
actionCode: '',
continueUrl: '',
}
},
methods: {
handleResetPassword: function() {
var accountEmail;
firebase.auth().verifyPasswordResetCode(actionCode).then(function(email) {
var accountEmail = email;
firebase.auth().confirmPasswordReset(this.actionCode, this.passwordNew).then(function(resp) {
alert("Password reset success");
this.$router.push('hello')
}).catch(function(error) {
// Error occurred during confirmation. The code might have expired or the
// password is too weak.
console.log("error 1")
});
}).catch(function(error) {
// Invalid or expired action code. Ask user to try to reset the password
// again.
console.log("error 2")
});
},
}
}
From Firebase documentation:
Some user management actions, such as updating a user's email address
and resetting a user's password, result in emails being sent to the
user. These emails contain links that recipients can open to complete
or cancel the user management action. By default, user management
emails link to the default action handler, which is a web page hosted
at a URL in your project's Firebase Hosting domain.
link: https://firebase.google.com/docs/auth/custom-email-handler
You need to get those parameters and store them on variables, from firebase documentation i got those snippets and just wrote the getParameterByName function:
function getParameterByName( name ){
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
// Get the action to complete.
var mode = getParameterByName('mode');
// Get the one-time code from the query parameter.
var actionCode = getParameterByName('oobCode');
// (Optional) Get the continue URL from the query parameter if available.
var continueUrl = getParameterByName('continueUrl');
You need to get those parameters first and verify the actioncode on the verifyPasswordResetCode method, then you can change the password and store it along with the action code to the method.
In your export default :
data: function() {
return {
passwordNew: '',
passwordConfirm: '',
mode: mode,
actionCode: actionCode,
continueUrl: continueUrl,
}
},
methods: {
handleResetPassword: function() {
var passwordNew = this.passwordNew
var actionCode = this.actionCode
firebase.auth().verifyPasswordResetCode(actionCode).then(function(email) {
console.log("ActionCode: "+ actionCode);
firebase.auth().confirmPasswordReset(actionCode, passwordNew).then(function(resp) {
alert("Password reset success");
this.$router.push('hello')
}).catch(function(error) {
console.log("error 1"+ error)
});
}).catch(function(error) {
console.log("Action code is invalid"+ error)
});
},
}

Categories

Resources