Stripe Exception error (Must provide source or customer) - javascript

im trying to working on this project https://www.youtube.com/watch?v=bu0J-j5qYas
so i can charge multiple times with dummy credit-card.
But i got exception error message when i try to check out, it say must provide source or customer, below is the javascript i wrote.
Stripe.setPublishableKey(''); // im not showingt this key (censored)
var $form = $('#checkout-form');
$form.submit(function(event) {
$('#charge-error').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) {
$('#charge-error').removeClass('hidden');
$('#charge-error').text(response.error.message);
$form.find('button').prop('disabled', false);
} else {
var token = response.id;
$form.append($('<input type="hidden" name="stripeToken" />').val(token)); // this will generate the stripeToken
// Submit the form:
$form.get(0).submit();
}
}
and i make this functionc below inside the controller directory just like the guide say
public function postCheckout(Request $request)
{
if (!Session::has('cart')) {
return redirect()->route('shop.shoppingCart');
}
$oldCart = Session::get('cart');
$cart = new Cart($oldCart);
Stripe::setApiKey(''); // not showing this key (censored)
try {
Charge::create(array(
"amount" => $cart->totalPrice * 100,
"currency" => "usd",
"source" => $request->input('stripeToken'), // obtained with first code i wrote above
"description" => "Test Charge"
));
} catch (\Exception $e) {
return redirect()->route('checkout')->with('error', $e->getMessage());
}
Session::forget('cart');
return redirect()->route('product.index')->with('success', 'Successfully purchased products!');
}
}
it keep return the catch that throw exception error message, is this mean it failed to get the stripetoken, how am i suppose to fix this? please help me

hi i think i figured out the problem, i rest the the api keys and also i check your spaces between the quotation marks in the public and secret keys,
Stripe.setPublishableKey('pk_anjndjxnh8hih9u220822');
and
Stripe::setApiKey('sk_dkneijhf9u9ue9ujednf9hefnie'); // not showing this key (censored)

try this Stripe: Must provide source or customer it is work for me!
just adding script with jquery-3.1.1.min.js like <script type="text/javascript" src="/javascripts/jquery-3.1.1.min.js"></script> before calling your checkout js file.

Related

Handling a Stripe customer creation error client side

I've been using Stripe to successfully process payments. The payment intent is created in PHP on the server and there is client side scripting in javascript to set up and call the payment intent script and handle the results.
If something like a card declined happens, then this is handled fine. However if there is a different kind of problem then although I can successfully trap this error server side, I've been unable to work out how to handle it client side and display a useful error message to the user.
This is my client side code:
var stripe = "***HIDDEN***";
var stripesetup = "/stripecreate.php";
var subscriptionid = document.getElementById("subscriptionid").value;
var email = document.getElementById('email').value;
// The items the customer wants to buy
var purchase = {
items: [{ id: subscriptionid }]
};
// Disable the button until we have Stripe set up on the page
document.getElementById("btn-checkout").disabled = true;
fetch(stripesetup, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(purchase)
}).then(function(result) {
/* This is where the error should be trapped, however result isn't the value from the server side script */
return result.json();
}).catch( (message) => {
/* Have also been trying to handle 'message' in here but without success */
}).then(function(data) {
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
fontFamily: 'Arial, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#32325d"
}
},
invalid: {
fontFamily: 'Arial, sans-serif',
color: "#fa755a",
iconColor: "#fa755a"
}
};
// Stripe injects an iframe into the DOM
var card = elements.create("card", { style: style });
card.mount("#card-element");
/*
var cardNumberElement = elements.create('cardNumber');
cardNumberElement.mount("#card-element");
var cardExpiryElement = elements.create('cardExpiry');
cardExpiryElement.mount("#cardexpiry-element");
*/
card.on("change", function (event) {
// Disable the Pay button if there are no card details in the Element
document.getElementById("btn-checkout").disabled = event.empty;
document.querySelector("#shopvalidation").textContent = event.error ? event.error.message : "";
});
var form = document.getElementById("shopform5");
form.addEventListener("submit", function(event) {
event.preventDefault();
// Complete payment when the submit button is clicked
payWithCard(stripe, card, data.clientSecret);
});
});
// Calls stripe.confirmCardPayment
// If the card requires authentication Stripe shows a pop-up modal to
// prompt the user to enter authentication details without leaving your page.
var payWithCard = function(stripe, card, clientSecret) {
loading(true);
stripe
.confirmCardPayment(clientSecret, {
receipt_email: email,
payment_method: {
card: card
}
})
.then(function(result) {
if (result.error) {
// Show error to your customer
showError(result.error.message);
} else {
// The payment succeeded!
orderComplete(result.paymentIntent.id);
}
});
};
/* ------- UI helpers ------- */
// Shows a success message when the payment is complete
var orderComplete = function(paymentIntentId) {
loading(false);
document.getElementById("btn-checkout").disabled = true;
location.href="/thank-you";
};
// Show the customer the error from Stripe if their card fails to charge
var showError = function(errorMsgText) {
loading(false);
var errorMsg = document.querySelector("#shopvalidation");
errorMsg.textContent = "Unfortunately your payment has been unsuccessful due to "+errorMsgText+" Please contact us for more information";
setTimeout(function() {
errorMsg.textContent = "";
}, 10000);
};
// Show a spinner on payment submission
var loading = function(isLoading) {
if (isLoading) {
// Disable the button and show a spinner
document.getElementById("btn-checkout").disabled = true;
document.querySelector("#lds-ring").classList.remove("invisible");
document.querySelector("#button-text").classList.add("invisible");
} else {
document.getElementById("btn-checkout").disabled = false;
document.querySelector("#lds-ring").classList.add("invisible");
document.querySelector("#button-text").classList.remove("invisible");
}
};
On the server, the payment intent is being created with this:
try {
$customer = \Stripe\Customer::create([
'name' => $fullname,
'email' => $email,
'phone' => $telephone,
"shipping" => [
'name' => $fullname,
"address" => [
"line1" => $address1,
"line2" => $address2,
"city" => $town,
"state" => $county,
"country" => $countrycode
],
],
"address" => [
"line1" => $billingaddress1,
"line2" => $billingaddress2,
"city" => $billingtown,
"state" => $billingcounty,
"country" => $billingcountrycode
],
'description' => $userid
]);
$stripeid = $customer->id;
} catch(\Stripe\Exception\CardException $e) {
// Since it's a decline, \Stripe\Exception\CardException will be caught
echo 'Status is:' . $e->getHttpStatus() . '\n';
echo 'Type is:' . $e->getError()->type . '\n';
echo 'Code is:' . $e->getError()->code . '\n';
echo 'Param is:' . $e->getError()->param . '\n';
echo 'Message is:' . $e->getError()->message . '\n';
die();
} catch (\Stripe\Exception\RateLimitException $e) {
// Too many requests made to the API too quickly
echo json_encode(['error' => $e->getMessage()]);
die();
} catch (\Stripe\Exception\InvalidRequestException $e) {
// Invalid parameters were supplied to Stripe's API
echo json_encode(['error' => $e->getMessage()]);
die();
} catch (\Stripe\Exception\AuthenticationException $e) {
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
echo json_encode(['error' => $e->getMessage()]);
die();
} catch (\Stripe\Exception\ApiConnectionException $e) {
// Network communication with Stripe failed
echo json_encode(['error' => $e->getMessage()]);
die();
} catch (\Stripe\Exception\ApiErrorException $e) {
// Display a very generic error to the user, and maybe send
// yourself an email
echo json_encode(['error' => $e->getMessage()]);
die();
} catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
echo json_encode(['error' => $e->getMessage()]);
die();
}
}
An "\Stripe\Exception\InvalidRequestException" is being thrown in my testing when I delibrately put in an invalid phone number. This is being returned by my stripecreate.php script:
{"error":"Invalid string: 0123456789...0123456789; must be at most 20 characters"}
I would expect this to be handled in the first part of the promise indicated in my client side script above, however the result is returning this when echoed to the console:
Response { type: "basic", url: "https://www.HIDDEN*****/stripecreate.php", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers(11), body: ReadableStream, bodyUsed: false }
​
body: ReadableStream { locked: true }
​
bodyUsed: true
​
headers: Headers(11) { "cache-control" → "no-store, no-cache, must-revalidate", "content-length" → "82", "content-type" → "application/json", … }
​
ok: true
​
redirected: false
​
status: 200
​
statusText: "OK"
​
type: "basic"
​
url: "https://www.HIDDEN*****/stripecreate.php"
​
<prototype>: ResponsePrototype { clone: clone(), arrayBuffer: arrayBuffer(), blob: blob(), … }
I expect this is me not correctly understanding how the promise structure is working and how I can get the response text from the server so I can check for an error and display it.
The next .then in the promise carries on execution even though I want it to stop at that point.
Been scratching my head over this one all day. Any help gratefully received.
Seems like your server is responding with JSON & 200 status code, so the first .then() callback only parses the response and moves on.
The status of the response being 200, it is unlikely that it'll be caught by the .catch() function too.
So you'd likely want to handle this response in the following .then() call.
Have you tried responding with a different response code (4xx) or (5xx) to see if that triggers .catch() callback?

Show NodeJS Errors in main html file itself

I made a form using NodeJs, i made some validations of input that show errors when user enter wrong values, the problem here is that the error appear on a new blank page but i need the error to appear on the main html file itself with cool styling
here's the live site http://mido.sundays.org.uk
I tried to make post request on the same route to see if the error will appear on the same page or not but the page turned to white blank page with the text inside
app.post('/', function (req, res) {
const SchemaValidation = {
name: joi.string().min(4).required().error(() => {
return {
message: 'Name is required. (min:4 chars)',
};
}),
email: joi.string().email().error(() => {
return {
message: 'Email field can\'t be Empty',
};
}),
phone: joi.string().min(8).max(14).required().error(() => {
return {
message: 'Valid Phone number is Required (min:8 characters - max: 14 characters)',
};
}),
university: joi.string().required().error(() => {
return {
message: 'University Field is Required',
};
}),
faculty: joi.string().required().error(() => {
return {
message: 'Faculty Field is Required',
};
}),
academicyear: joi.string().required().error(() => {
return {
message: 'Academic Year Field is Required and should range from 1-6',
};
}),
workshop: joi.array()
.items(joi.string().error(() => {
return {
message: 'You Should pickup 2 Committees',
};
})),
first_choice: joi.string().required().error(() => {
return {
message: 'You should pickup first choice',
};
}),
second_choice: joi.string().required().error(() => {
return {
message: 'You should pickup second choice',
};
}),
};
joi.validate(req.body,SchemaValidation,(err, result) => {
if(err) {
res.send(`<p style='color:red; text-align:center; margin-top:20px;'>${err.details[0].message}</p>`);
return; // don't try saving to db if the schema isnt valid
}
else
res.send(`<p style='color:green; text-align:center; margin-top:20px;'>Successfully Posted Data</p>`);
})
});
All what i need is to show the error in the same page and prevent the submit..
To solve this problem, I highly racommand you to use Pug.js (Template Engine), because you can't pass parameters into a specific page. By using a template engine, you can pass data as object, and render them with res.render('index', {error: res.error.message}).
You will be able to output into the page from server side the error object displaying whatever you needed to display!
res.send('content') basically it's a document.write()
https://pugjs.org/api/getting-started.html
Is there a reason you can't do the validation on the front end before submitting the form? That is usually the preferred way. You can have some backend validation so that you don't get bad data into your db but once you send a request you need to send a response back and in your case the response is the message not the entire HTML page. You can create a validation by adding an event listener to your submit button then using Ajax once you validate to send the data to the backend or you can use Bootstrap's built in validation and not mess with Ajax just through the form action. https://getbootstrap.com/docs/4.0/components/forms/#validation

Server side validation in Express compatible with a single page Angular application

I would like to perform server side validation, preferably with expressValidator. When saving a resource, I check to see if it is valid. If it's not valid what should I return?
There are examples:
http://blog.ijasoneverett.com/2013/04/form-validation-in-node-js-with-express-validator/
https://github.com/ctavan/express-validator
Unfortunately, I can't figure out my answer from that.
In Angular, I am using the $resource service. When I do a save, and there is a validation error, how should the server send this back? Note, this is a single page application.
Also, how should I handle this on the client side? Is this technically a success call?
Please, I am not looking for any instant, ajax, check per field solution. I want to submit save, if there is a problem, I would like to return the errors so that Angular can handle them. This does not need to be the perfect solution, just something to set me on the right track.
I am not handing the Angular code in an special way at the moment:
Controller:
$scope.saveTransaction = function (transaction) {
transactionData.saveTransaction(transaction);
}
Service
saveTransaction: function(transaction) {
return resource.save(transaction);
}
The server side code looks as follows:
app.post('/api/transactions', function (req, res) {
var transaction;
req.assert('amount', 'Enter an amount (numbers only with 2 decimal places, e.g. 25.50)').regex(/^\d+(\.\d{2})?$/);
var errors = req.validationErrors();
var mapped = req.validationErrors(true);
if (mapped) {console.log("MAPPED")};
//console.log(mapped);
if(!errors) {
console.log("Passed");
transaction = new TransactionModel({
date: req.body.date,
description: req.body.description,
amount: req.body.amount
});
transaction.save(function (err) {
if (!err) {
return console.log("created");
} else {
return console.log("err");
}
return res.send(transaction);
})
}
else {
console.log("Errors");
res.send(errors);
// res.render('Transaction', {
// title: 'Invalid Transaction',
// message: '',
// errors: errors
// });
}
});
You could send and handle "better" errors:
SERVER
res.json(500, errors)
CLIENT
resource.save(tran).then(function(){
//it worked
},
function(response) {
//it did not work...
//see response.data
});

Create own plugin in phonegap for windows phone

I want to pass string value from c# to JavaScript using JSON. So I created an example plugin name: Echo.cs (in CordovaWP namespace), and an "echo" method in Echo class. Like this tutorial.
In index.js, I called:
cordova.exec(function (result)
{
alert("OK");
}, function (error) {
alert("KO");
}, "CordovaWP.Echo", "echo", "ok");
But I can't get debug in echo method. And have nothing found!
Use as below:
cordova.exec(function (result)
{
alert("OK");
}, function (error) {
alert("KO");
}, "CordovaWP.Echo", "echo", ["ok"]);
Parameters should always be sent as an array from JS to cs
Please can you also post your CS code:
Check sample below SMS example:
JS:
var sendSMS = function(phoneNumber,smsBody){
cordova.exec(function(){console.log("success SMS");},function(){console.log("Error SMS");},"SMS", "sendSMS", [phoneNumber,smsBody]);
};
CS:
namespace Cordova.Extension.Commands{
public class SMS : BaseCommand
{
public void sendSMS(string arg)
{
string recipient = JsonHelper.Deserialize<string[]>(arg)[0];
string smsBody = JsonHelper.Deserialize<string[]>(arg)[1];
SmsComposeTask composeSMS = new SmsComposeTask();
composeSMS.Body = smsBody;
composeSMS.To = recipient;
composeSMS.Show();
this.DispatchCommandResult();
}
}
}

Jquery ajax not working (Laravel 4)

I use jquery ajax to add data to database. When i click submit button, my page return blank. I use firebug to debug and see message: 500 (Internal Server Error).
routes.php
Route::controller('subscribers', 'SubscribersController');
SubscribersController.php
class SubscribersController extends \BaseController {
//The method to show the form to add a new feed
public function getIndex() {
//We load a view directly and return it to be served
return View::make('subscribe_form');
}
//This method is to process the form
public function postSubmit() {
//We check if it's really an AJAX request
if(Request::ajax()) {
$validation = Validator::make(Input::all(), array(
//email field should be required, should be in an email
//format, and should be unique
'email' => 'required|email|unique:subscribers, email'));
if($validation->fails()) {
return $validation->errors()->first();
} else {
$create = Subscribers::create(array(
'email' => Input::get('email')
));
//If successful, we will be returning the '1' so the form
//understands it's successful or if we encountered an unsuccessful creation attempt,
//return its info
return $create?'1':'We could not save your address to our system, please try again later';
}
} else {
return Redirect::to('subscribers');
}
}
}
view file:
{{--Form Starts Here --}}
{{Form::open(array('url' => URL::to('subscribers/submit'), 'method' => 'post'))}}
<p>Simple Newsletter Subscription</p>
{{Form::text('email', null, array('placeholder'=>'Type your E-mail address here'))}}
{{Form::submit('Submit!')}}
{{Form::close()}}
{{--Form Ends Here --}}
{{--This div will show the ajax response --}}
<div class="content"></div>
{{-- Because it'll be sent over Ajax, we add the jQuery source --}}
{{HTML::script('http://code.jquery.com/jquery-1.11.0.min.js') }}
<script type="text/javascript">
//Even though it's on footer, I just like to make
//sure that DOM is ready
$(function() {
//We hide de the result div on start
$('div.content').hide();
//This part is more jQuery related. In short, we make an Ajax post request and get
//the response back from server
$('input[type="submit"]').click(function(e) {
e.preventDefault();
$.post('http://localhost/laravel-blueprint/newsletter/public/subscribers/submit', {email: $('input[name="email"]').val()
}, function($data) {
if($data == '1') {
$('div.content')
.hide()
.removeClass('success error')
.addClass('success')
.html('You\'ve successfully subscribed to our newsletter')
.fadeIn('fast');
} else {
//This part echos our form validation errors
$('div.content')
.hide().removeClass('success error')
.addClass('error')
.html('There has been an error occurred: <br /><br />'+$data)
.fadeIn('fast');
}
});
});
//We prevented to submit by pressing enter or any other way
$('form').submit(function(e) {
e.preventDefault();
$('input[type="submit"]').click();
});
});
</script>
i use laravel 4
log-access:
127.0.0.1 - - [11/Mar/2014:17:54:41 +0700] "POST /laravel-blueprint/newsletter/public/subscribers/submit HTTP/1.1" 500 381
Any solution?
In order for your code to work, do the following changes:
SUBSCRIBERS CONTROLLER
class SubscribersController extends \BaseController {
public function getIndex() {
return View::make('subscribe_form');
}
public function postSubmit() {
if(Request::ajax()) {
$validation = Validator::make(Input::all(),
['email' => 'required|email|unique:subscribers,email']);
if($validation->fails()) {
return $validation->errors()->first();
} else {
// Note here that the model is Subscriber and not Subscribers
// This is the default convention for the subscribers table
$create = Subscriber::create(array(
'email' => Input::get('email')
));
return $create ? '1' : 'We could not save your address';
}
} else {
return Redirect::to('subscribers');
}
}
}
IMPORTANT FOR SUBSCRIBER MODEL
class Subscriber extends Eloquent {
// I don't know if you have timestamps enabled, but if not this is necessary
public $timestamps = false;
// Must be present for mass assignment to work (Subscriber::create)
protected $fillable = array('email');
}
Comment
500 (Internal Server Error) might be caused due to a PHP fatal.
Do you have error_reporting on?
If not, try
error_reporting(E_ALL); ini_set('display_errors', 1);
and check.

Categories

Resources