Friday, May 17, 2024
 Popular · Latest · Hot · Upcoming
131
rated 0 times [  136] [ 5]  / answers: 1 / hits: 26975  / 7 Years ago, tue, february 28, 2017, 12:00:00

I'm trying to integrate Stripe for my shopping cart project. I can't get my checkout form to submit. I keep getting this error message: Must provide source or customer. Either I didn't set up my Stripe account correctly or I'm missing some parameters in my javascript. I've spent hours on this problem and still can't figure it out.



This is from Stripe's log:

Parsed Request POST Body



{
amount: 21000,
currency: usd,
description: Test Charge
}


Response Body



{
error: {
type: invalid_request_error,
message: Must provide source or customer.
}
}


This is my app.js



var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var expressHbs = require('express-handlebars');
var mongoose = require('mongoose');
var session = require('express-session');
var passport = require('passport');
var flash = require('connect-flash');
var validator = require('express-validator');
var MongoStore = require('connect-mongo')(session);

var routes = require('./routes/index');
var userRoutes = require('./routes/user');

var app = express();

mongoose.connect('localhost:27017/shopping');
require('./config/passport');

// view engine setup
app.engine('.hbs', expressHbs({defaultLayout: 'layout', extname: '.hbs'}));
app.set('view engine', '.hbs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(validator());
app.use(cookieParser());
app.use(session({
secret: 'mysupersecret',
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
cookie: { maxAge: 180 * 60 * 1000 }
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));

app.use(function(req, res, next){
res.locals.login = req.isAuthenticated();
res.locals.session = req.session;
next();
});

app.use('/user', userRoutes);
app.use('/', routes);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// render the error page
res.status(err.status || 500);
res.render('error');
});

module.exports = app;


This is my index.js:



var express = require('express');
var router = express.Router();
var Cart = require('../models/cart');

var Product = require('../models/product');

/* GET home page. */
router.get('/', function(req, res, next) {
var successMsg = req.flash('success')[0];
Product.find(function(err, docs) {
var productChunks = [];
var chunkSize = 3;
for (var i = 0; i < docs.length; i += chunkSize) {
productChunks.push(docs.slice(i, i + chunkSize));
}
res.render('shop/index', { title: 'Shopping Cart', products: productChunks, successMsg: successMsg, noMessages: !successMsg});
});
});

router.get('/add-to-cart/:id', function(req, res, next) {
var productId = req.params.id;
var cart = new Cart(req.session.cart ? req.session.cart : {});

Product.findById(productId, function(err, product){
if (err) {
return res.redirect('/');
}
cart.add(product, product.id);
req.session.cart = cart;
console.log(req.session.cart);
res.redirect('/');
});
});

router.get('/shopping-cart', function(req, res, next) {
if (!req.session.cart) {
return res.render('shop/shopping-cart', {products: null});
}
var cart = new Cart(req.session.cart);
res.render('shop/shopping-cart', {products: cart.generateArray(), totalPrice: cart.totalPrice});
});

router.get('/checkout', function(req, res, next) {
if (!req.session.cart) {
return res.redirect('/shopping-cart');
}
var cart = new Cart(req.session.cart);
var errMsg = req.flash('error')[0];
res.render('shop/checkout', {total: cart.totalPrice, errMsg: errMsg, noError: !errMsg});
});

router.post('/checkout', function(req, res, next) {
if (!req.session.cart) {
return res.redirect('/shopping-cart');
}
var cart = new Cart(req.session.cart);
var stripe = require(stripe)(
**hidden**
);

stripe.charges.create({
amount: cart.totalPrice * 100,
currency: usd,
source: req.body.stripeToken,
description: Test Charge
}, function(err, charge) {
if (err) {
req.flash('error', err.message);
return res.redirect('/checkout');
}
req.flash('success', 'Successfully bought product!');
req.cart = null;
res.redirect('/');
});
});

module.exports = router;


This is my checkout.js:



Stripe.setPublishableKey('**hidden**');

var $form = $('checkout-form');

$form.submit(function(event) {
$('#charge-errors').addClass('hidden');
$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(),
name: $('#card-name').val()
}, stripeResponseHandler);
return false;
});

function stripeResponseHandler(status, response) {
if (response.error) { // Problem!

// Show the errors on the form
$('#charge-errors').text(response.error.message);
$('#charge-errors').removeClass('hidden');
$form.find('button').prop('disabled', false); // Re-enable submission

} else { // Token was created!

// Get the token ID:
var token = response.id;

// Insert the token 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();
}
};


This is my checkout form (.hbs):



<div class=row>
<div class=col-sm-6 col-md-6 col-md-offset-3 col-sm-offset-3>
<h1>Checkout</h1>
<h4>Your Total: ${{total}}</h4>
<div id=charge-error class=alert alert-danger {{# if noError}}hidden{{/if}}>
{{errMsg}}
</div>
<form action=/checkout method=post id=checkout-form>
<div class=row>
<div class=col-xs-12>
<div class=form-group>
<label for=name>Name</label>
<input type=text id=name class=form-control required>
</div>
</div>
<div class=col-xs-12>
<div class=form-group>
<label for=name>Address</label>
<input type=text id=address class=form-control required>
</div>
</div>
<div class=col-xs-12>
<div class=form-group>
<label for=name>Name on Card</label>
<input type=text id=card-name class=form-control required>
</div>
</div>
<div class=col-xs-12>
<div class=form-group>
<label for=name>Credit Card Number</label>
<input type=text id=card-number class=form-control required>
</div>
</div>
<div class=col-xs-6>
<div class=form-group>
<label for=name>Expiration Month</label>
<input type=text id=card-expiry-month class=form-control required>
</div>
</div>
<div class=col-xs-6>
<div class=form-group>
<label for=name>Expiration Year</label>
<input type=text id=card-expiry-year class=form-control required>
</div>
</div>
<div class=col-xs-12>
<div class=form-group>
<label for=name>
CVC</label>
<input type=text id=card-cvc class=form-control required>
</div>
</div>
</div>
<button type=submit class=btn btn-success>Buy Now</button>
</form>
</div>
</div>

<script type=text/javascript src=https://js.stripe.com/v2/></script>
<script type=text/javascript src=javascripts/checkout.js></script>

More From » node.js

 Answers
19

A payment flow with Stripe is divided in two steps:




  1. Client-side, in your frontend code, you collect and tokenize the customer's payment information using Checkout or Elements, then send the resulting token to your backend server.


  2. Server-side, in your backend code, you use the token in an API request, e.g. to create a charge or a customer.




The code you shared is for the first step. However, the error message you mentioned:




Must provide source or customer.




occurs in the second step. This error is returned by Stripe's API when you send a charge creation request without a source or customer parameter.



You need to check your server-side code to figure out what the problem is exactly. You can also check the logs of all requests sent by your integration in your dashboard: https://dashboard.stripe.com/test/logs?method=not_get.


[#58746] Saturday, February 25, 2017, 7 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
parkernotnamedt

Total Points: 539
Total Questions: 90
Total Answers: 99

Location: Hong Kong
Member since Tue, Oct 19, 2021
3 Years ago
;