I'm trying to integrate stripe.js into a web app I'm working on, however I'm being thrown the following error:
Cannot read property 'stripeToken' of undefined
The clientside is setting the hidden input of the token but for some reason, the server can't pull it this:
var stripeToken = request.body.stripeToken;
Any ides as to why this might be?
Client-side JS
jQuery(function($) {
$('#payment-form').submit(function(event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
Stripe.card.createToken({
number: $('.card-number').val(),
cvc: $('.card-cvc').val(),
exp_month: $('.card-expiry-month').val(),
exp_year: $('.card-expiry-year').val()
}, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
});
function stripeResponseHandler(status, response) {
// Grab the form:
var $form = $('#payment-form');
if (response.error) { // Problem!
// Show the errors on the form:
$form.find('.payment-errors').text(response.error.message);
$form.find('.submit').prop('disabled', false); // Re-enable submission
} else { // Token was created!
// Get the token ID:
var token = response.id;
// Insert the token ID into the form so it gets submitted to the server:
$form.append($('<input type="hidden" name="stripeToken">').val(token));
// Submit the form:
$form.get(0).submit();
}
};
jQuery(function($) {
$('[data-numeric]').payment('restrictNumeric');
$('.cc-number').payment('formatCardNumber');
$('.cc-exp').payment('formatCardExpiry');
$('.cc-cvc').payment('formatCardCVC');
$.fn.toggleInputError = function(erred) {
this.parent('.form-group').toggleClass('has-error', erred);
return this;
};
$('form').submit(function(e) {
e.preventDefault();
var cardType = $.payment.cardType($('.cc-number').val());
$('.cc-number').toggleInputError(!$.payment.validateCardNumber($('.cc-number').val()));
$('.cc-exp').toggleInputError(!$.payment.validateCardExpiry($('.cc-exp').payment('cardExpiryVal')));
$('.cc-cvc').toggleInputError(!$.payment.validateCardCVC($('.cc-cvc').val(), cardType));
$('.cc-brand').text(cardType);
$('.validation').removeClass('text-danger text-success');
$('.validation').addClass($('.has-error').length ? 'text-danger' : 'text-success');
});
});
Server-side JS
app.post('/', function(req, res) {
var stripeToken = request.body.stripeToken;
var charge = stripe.charges.create({
amount: 1000, // amount in cents, again
currency: "usd",
source: stripeToken,
description: "Example charge"
}, function(err, charge) {
if (err && err.type === 'StripeCardError') {
// The card has been declined
}
});
});
Form (jade)
form(novalidate='', autocomplete='on', method='POST' id="payment-form")
.form-group
label.control-label(for='cc-number')
| Card number formatting
small.text-muted
| [
span.cc-brand
| ]
input#cc-number.input-lg.form-control.cc-number(type='tel', autocomplete='cc-number', placeholder='•••• •••• •••• ••••', required='')
.form-group
label.control-label(for='cc-exp') Card expiry formatting
input#cc-exp.input-lg.form-control.cc-exp(type='tel', autocomplete='cc-exp', placeholder='•• / ••', required='')
.form-group
label.control-label(for='cc-cvc') Card CVC formatting
input#cc-cvc.input-lg.form-control.cc-cvc(type='tel', autocomplete='off', placeholder='•••', required='')
button.btn.btn-lg.btn-primary(type='submit' class='submit') Submit
h2.validation
our request is in the variable req not request
this var stripeToken = request.body.stripeToken; should be var stripeToken = req.body.stripeToken;
Related
I am getting this error and I have no clue about this and trying to sort out the things and tried many things but nothing works. Kindly check the errors below:
Notice: Undefined index: stripeToken in
/opt/lampp/htdocs/fullbrick/thankYou.php on line 42 NULL Fatal error:
Uncaught Stripe\Error\InvalidRequest: Must provide source or customer.
in /opt/lampp/htdocs/fullbrick/stripe-php/lib/ApiRequestor.php:181
from API request 'req_cuGvSG7abb9bzS' Stack trace: #0
/opt/lampp/htdocs/fullbrick/stripe-php/lib/ApiRequestor.php(144):
Stripe\ApiRequestor::_specificAPIError('{\n "error": {\n...', 400,
Array, Array, Array) #1
/opt/lampp/htdocs/fullbrick/stripe-php/lib/ApiRequestor.php(430):
Stripe\ApiRequestor->handleErrorResponse('{\n "error": {\n...', 400,
Array, Array) #2
/opt/lampp/htdocs/fullbrick/stripe-php/lib/ApiRequestor.php(97):
Stripe\ApiRequestor->_interpretResponse('{\n "error": {\n...', 400 ,
Array) #3
/opt/lampp/htdocs/fullbrick/stripe-php/lib/ApiOperations/Request.php(56):
Stripe\ApiRequestor->request('post', '/v1/charges', Array, Array) #4
/opt/lampp/htdocs/halfdrink/stripe-php/lib/ApiOperations/Create.php(23):
Stripe\ApiResource::_staticRequest('post', '/v1/charges', Array, NULL)
5 /opt/lampp/htdocs/fullbrick/thankYou.php(53): Stripe\Charge::create(Array) #6
{main} in
/opt/lampp/htdocs/fullbrick/stripe-php/lib/ApiRequestor.php on line
181
The code is:
<script>
// Errors For Stripe Payment Card Check
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Create a token or display an error when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the customer that there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
// Custom styling can be passed to options when creating an Element.
var style = {
base: {
// Add your base input styles here. For example:
fontSize: '16px',
color: "#32325d",
}
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
</script>
<form action="thankYou.php" method="post" id="payment-form">
<span class="bg-danger" id="payment_errors"></span>
<span class="bg-danger" id="card-errors"></span>
<div class="form-group col-md-6">
<label for="full_name">Full Name:</label>
<input class="form-control" type="text" name="full_name" id="full_name">
</div>
//Same as Email div, phone,address,city,state,zipcode,country,cardname,cardnumber,exp month, exp year, cvc
<button type="submit" class="btn btn-primary" id="checkout_button" style="display:none;">Check Out >></button>
</form>
On thanYou.php
//Getting Variable details like
$full_name = $_POST['full_name']; // same as email,phone, address,city ...
$metadata = array(
"cart_id" => $cart_id,
"tax" => $tax,
"sub_total" => $sub_total,
);
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_hiQjZlN9oJ9GcLGAlPVwAvfq"); // secret Key
// Token is created using Checkout or Elements!
// Get the payment token ID submitted by the form:
$token = $_POST['stripeToken']; // Here not getting token
var_dump($token);
try{ . // Here not getting inside the try because token is null
$charge = \Stripe\Charge::create([
'amount' => 999,
'currency' => 'usd',
'description' => 'Example charge',
'source' => $token,
'receipt_email' => $email,
'metadata' => $metadata,
]);
}catch(\Stripe\Error\card $e){
echo $e;
}
This ApiRequestor.php is the main problem I guess.
I'm going to try and be thorough as possible. So what I'm trying to do is charge a user a percentage of the overall total that is calculated. How do we get the total? Well, the total cost is depended upon the progression of questions the user answers.
If the user needs a specific service then the cost might increase a bit, say to $100, but we're wanting to charge just 10% of that total that constantly changes like stated before. Currently, the amount is hardcoded, but since the amount changes depending on their services select, I can't have it hard coded.
I'm new to Stripe and Node but is there an easy way such as 'document.getElementById'? of something similar? The charge and everything work correctly but I believe I'm getting confused on the routing.
My HTML form (with the area where the total will be displayed):
<div class="" style="margin-top: 60px;">
<h2 class="quote-info">Estimated total: $<span id="new_text"></span> USD</h2>
<h2 class="quote-info">Reservation deposit: $<span id="new_text2"></span> USD</h2>
</div>
<!-- Payment form -->
<form action="/charge" method="post" id="payment-form">
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element">
<!-- a Stripe Element will be inserted here. -->
</div>
<!-- Used to display form errors -->
<div id="card-errors"></div>
</div>
<input type="hidden" name="totalAmount" value="1000">
<button>Submit Payment</button>
</form>
My script tag that's found at the bottom of my HTML file that contains the form above:
<script type="text/javascript">
//Create a Stripe client
var stripe = Stripe('my_key_should_go_here');
// Create an instance of Elements
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
lineHeight: '24px',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
// Create an instance of the card Element
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>
card.mount('#card-element');
// Handle real-time validation errors from the card Element.
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the user if there was an error
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
var formData = JSON.stringify({
mytoken: token.id
});
$.ajax({
type: "POST",
url: "/charge",
data: formData,
success: function(){alert("done")},
dataType: "json",
contentType: "application/json"
});
// alert("Created a token with value: "+token.id)
form.submit();
}
</script>
And lastly, my app.js file:
const express = require('express');
const stripe = require('stripe')('deleted_key');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
// Set Static Folder
app.use(express.static('public'));
// Index route
app.get('/charge', (req, res) => {
res.send();
});
// charge route
app.post('/charge', (req, res) => {
// const amount = 2500;
const amount = req.body.totalAmount;
stripe.customers.create({
email: "random#gmail.com",
source: req.body.mytoken
})
.then(customer => {
stripe.charges.create({
amount,
description:'specified service description here',
currency:'usd',
customer:customer.id
})})
.then(charge => res.send('success'));
});
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
My primary question is this, how would I go about obtaining the amount given in the 'new_text' area in my HTML file to use and charge the user in node?
To use the getElementById is to add an ID to your amount field first:
<input type="hidden" name="totalAmount" id="totalAmount" value="1000">
Then you can use the ID to get the value of the field:
const amount = document.getElementById("totalAmount").value;
Although, I can see that your input type is hidden - is that intentional?
Trying to charge a customer for a product registration. I've been following this tutorial upskillcourses.com. Which sets up a subscription. I' just trying to create a charge for a product.
I keep getting this error:
Stripe::CardError in Roadregistrations::RegistrationsController#create
Cannot charge a customer that has no active card
I've setup the stripe.js file:
app/assets/javascripts/
/* global $, Stripe */
//Document ready.
$(document).on('turbolinks:load', function(){
var theForm = $('#payment-form');
var submitBtn = $('#form-submit-btn');
//Set Stripe public key.
Stripe.setPublishableKey( $('meta[name="stripe-key"]').attr('content') );
//When user clicks form submit btn,
submitBtn.click(function(event){
//prevent default submission behavior.
event.preventDefault();
submitBtn.val("Processing").prop('disabled', true);
//Collect the credit card fields.
var ccNum = $('#card_number').val(),
cvcNum = $('#card_code').val(),
expMonth = $('#card_month').val(),
expYear = $('#card_year').val();
//Use Stripe JS library to check for card errors.
var error = false;
//Validate card number.
if(!Stripe.card.validateCardNumber(ccNum)) {
error = true;
alert('The credit card number appears to be invalid');
}
//Validate CVC number.
if(!Stripe.card.validateCVC(cvcNum)) {
error = true;
alert('The CVC number appears to be invalid');
}
//Validate expiration date.
if(!Stripe.card.validateExpiry(expMonth, expYear)) {
error = true;
alert('The expiration date appears to be invalid');
}
if (error) {
//If there are card errors, don't send to Stripe.
submitBtn.prop('disabled', false).val("Register and Pay");
} else {
//Send the card info to Stripe.
Stripe.createToken({
number: ccNum,
cvc: cvcNum,
exp_month: expMonth,
exp_year: expYear
}, stripeResponseHandler);
}
return false;
});
//Stripe will return a card token.
function stripeResponseHandler(status, response) {
//Get the token from the response.
var token = response.id;
//Inject the card token in a hidden field.
theForm.append($('<input type="hidden" name="user[stripe_card_token]">').val(token));
//Submit form to our Rails app.
theForm.get(0).submit();
}
});
Which it seems like the token is not being submitted with the form.
Not sure if I need both of these in my users_controller.rb:
# Only allow a trusted parameter "white list" through.
def roadregistration_params
params.require(:user).permit(:first_name, :last_name, :company, :street, :city, :state, :zip, :email, :phone, :roadshowcity, :stripe_card_token, :comments)
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:stripe_card_token, :password, :password_confirmation, :email, :first_name, :last_name, :company, :street, :city, :state, :zip, :phone, :roadshowcity, :comments) }
end
Then I have this in my user model:
attr_accessor :stripe_card_token
# If user passes validations (email, pass, etc.),
# Call stripe and tell stripe to set up a subscription
def save_with_registration
if valid?
#product_price = Objective.find(objective_id)
customer = Stripe::Customer.create(email: email, card: stripe_card_token, description: stripe_card_token.to_s)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => 9500,
:currency => "usd",
:description => "Roadshow Registration"
)
self.stripe_customer_token = customer.id
save!
end
end
customer = Stripe::Customer.create(email: 'example#gma.com')
=> #<Stripe::Customer:0x3ffd3a10e024 id=cus_A5CWbyto5ugmju> JSON: {
"id": "cus_A5CWbyto5ugmju",
"object": "customer",
"account_balance": 0,
"created": 1486585998,
"currency": null,
"default_source": null,
"delinquent": false,
"description": null,
"discount": null,
"email": "example#gma.com",
"livemode": false,
"metadata": {},
"shipping": null,
"sources": {"object":"list","data":[],"has_more":false,"total_count":0,"url":"/v1/customers/cus_A5CWbyto5ugmju/sources"},
"subscriptions": {"object":"list","data":[],"has_more":false,"total_count":0,"url":"/v1/customers/cus_A5CWbyto5ugmju/subscriptions"}
}
You just have to link card to the customer after creating the customer on stripe and before charging him:
customer = Stripe::Customer.create(email: email)
customer.sources.create(card: stripe_card_token) # <-- this
charge = Stripe::Charge.create(..
And I would advice to not send stripe_card_token in the customer object.
If you are on a version older than 2015-02-18 API version replace sources with cards.
Turbolinks was not being loaded in the app/assets/javascripts/application.js file. Fixing that issue allowed the stripe javascript to run and passed the stripe_card_token along.
Having a warm time trying to charge a card in Meteor. The error I get is: Exception while invoking method 'chargeCard' Error: Match error: Expected string, got object. I do get the modal where I typed in the email and card number but after pressing the pay button, in terminal I get the error message.
How to call the charge function properly? I cant find any tutorial that matches closely the way I implement it.
The setup is very basic. I also have jquery installed.
Template:
<template name="hello">
<form id="myForm">
<input type="text" id="amount" name="amount"/>
<input type="hidden" id="stripeToken" name="stripeToken"/>
<input type="hidden" id="stripeEmail" name="stripeEmail"/>
</form>
<hr>
<button id="customButton">Pay</button>
</template>
js:
if (Meteor.isClient) {
Template.hello.helpers({
});
Template.hello.events({
'click button': function (e) {
e.preventDefault();
var handler = StripeCheckout.configure({
key: 'pk_test_rand',
token: function(token) {
$("#stripeToken").val(token.id);
$("#stripeEmail").val(token.email);
$("#myForm").submit();
Meteor.call('chargeCard', token); // this seem not right?
}
});
// Showing the pop up Stripe dialog
var amount = $("#amount").val() *100;
// Open Checkout with further options
handler.open({
name: 'Demo Site',
description: '2 widgets ($20.00)',
amount: amount
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
}
});
Meteor.startup(function(){
$.getScript('https://checkout.stripe.com/checkout.js', function(){
// script has loaded
});
});
}
if (Meteor.isServer) {
Meteor.methods({
'chargeCard': function(stripeToken) {
check(stripeToken, String);
var Stripe = StripeAPI('sk_test_rand');
Stripe.charges.create({
source: stripeToken,
amount: 5000, // this is equivalent to $50
currency: 'usd'
}, function(err, charge) {
console.log(err, charge);
});
}
});
}
It seems you're passing the whole token object:
Meteor.call('chargeCard', token);
But your chargeCard() method expects a string:
check(stripeToken, String);
So you need to either pass only the token id:
Meteor.call('chargeCard', token.id);
or change your chargeCard() method to expect and use the whole token object:
Meteor.methods({
'chargeCard': function(stripeToken) {
check(stripeToken, Object);
var Stripe = StripeAPI('sk_test_rand');
Stripe.charges.create({
source: stripeToken.id,
...
I'm building a simple form.
This form get a birthday field.
I can select a date and persist it.
But when I reload the page, I have an error
Error: [ngModel:datefmt] Expected `2015-03-06T23:00:00.000Z` to be a date
I know how to resolve it. I need to convert my user.date_birthday to a Date.
So I tried this.
'use strict';
angular.module('TheNameApp')
.controller('SettingsCtrl', function ($scope, User, Auth) {
$scope.user = User.get();
$scope.errors = {};
console.log($scope.user); // display the resource
console.log($scope.user.date_birthday); //undefined
$scope.changeInformations = function(form) {
$scope.infos_submitted = true;
if(form.$valid) {
Auth.changeInformations({
gender: $scope.user.gender,
city: $scope.user.city,
country: $scope.user.country,
talent: $scope.user.talent,
date_birthday: $scope.user.date_birthday,
user_name: $scope.user.user_name,
email: $scope.user.email })
.then( function() {
$scope.infos_message = 'Done.'
})
.catch( function(err) {
err = err.data;
$scope.errors = {};
// Update validity of form fields that match the mongoose errors
angular.forEach(err.errors, function(error, field) {
form[field].$setValidity('mongoose', false);
$scope.errors[field] = error.message;
});
});
}
};
the .html
<div class="form-group">
<label>Birthday</label>
<input type="date" name="date_birthday" class="form-control" ng-model="user.date_birthday"/>
</div>
The user.date_birthday is not defined but I can see it in $scope.user
I need this for my next step
$scope.user.date_birthday = new Date($scope.user.date_birthday);
Why I can't see my attribute? How Can I resolve this?
Assuming your User is a resource, .get() is an async call. Use a callback:
User.get(function(user) {
user.date_birthday = new Date(user.date_birthday);
$scope.user = user;
});