Saving card details to customer using Stripe Elements - php

I have a little store I'm setting up, and so far, it's relatively simple. You can either order the product one time, weekly, or monthly.
I have set up the corresponding products in the Stripe Dashboard.
If the client sends that they want a recurring order, it creates a Customer with their information.
But whenever I try and create a recurring order, I receive a This customer has no attached payment source or default payment method. thrown in.
I'm using Stripe Elements, and since the card data never goes to my server, I'm not sure how to go about adding a payment method to this Customer.
Create subscription:
\Stripe\Subscription::create([
'customer' => $customer_id,
'items' => [
[
'price' => 'price_id_2',
'quantity' => $qty_1,
'price' => 'price_id_2',
'quantity' => $qty_2,
],
],
]);
$.post to send data to the PHP file
$.post('./secret.php', data, null, "json")
.done(function(data) {
clientSecret = data.client_secret;
stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: card,
}
}).then(function(result) {
if (result.error) {
console.log(result.error.message);
} else {
if (result.paymentIntent.status === 'succeeded') {
console.log("Payment success.");
document.getElementById("processing").classList.add("hide");
document.getElementById("order-success").classList.remove("hide");
}
}
})
})
.fail(function(xhr, status, error) {
document.getElementById("processing").classList.add("hide");
document.getElementById("order-failure").classList.remove("hide");
});
My one-time order works fine, but I just can't understand how to do this. The Docs show "Saving Card Data" as a deprecated utility, so I'm not sure what to do.

It sounds like you likely want to save a card during the payment process: https://stripe.com/docs/payments/save-during-payment

Related

Pass payment method id to create charge

What is the issue about?
I am trying to pass payment method id and customer to create single charge in php: https://stripe.com/docs/api/charges/create
I have successfully retrieved the Payment Method id for Payment Methods For Single Charges
Here is the code i JQuery
cardButton.addEventListener('click', (e) => {
stripe.createPaymentMethod(
"card", cardElement, {
billing_details: {
name: cardHolderName.value
}
}
).then(function(result) {
//Payment Method id retrieved here...
});
});
I have stripe customer ID, I also have stripe Payment Method id.
This is not about subscription...
As per the docs, there is no payment method property. How will I pass this info?
The Charges API (https://stripe.com/docs/api/charges/create) does not support passing a PaymentMethod object — it's an older API(https://stripe.com/docs/payments/legacy-apis) and you would generally not use it in a new integration today.
Instead, you would use the PaymentMethod that you obtained with a PaymentIntent on the backend. For example:
https://stripe.com/docs/payments/accept-a-payment-synchronously
if data['payment_method_id']
# Create the PaymentIntent
intent = Stripe::PaymentIntent.create(
payment_method: data['payment_method_id'], # from frontend
amount: 1099,
currency: 'usd',
confirmation_method: 'manual',
confirm: true,
)
# check intent.status for next steps...

processor_declined response for paypal braintree transaction

I have used non business account to create sandbox accounts.
Transactions are created:-
$amount = $_POST["amount"];
$nonce = $_POST["payment_method_nonce"];
$result = $gateway->transaction()->sale([
'amount' => $amount,
'paymentMethodNonce' => $nonce,
'options' => [
'submitForSettlement' => true]
]);
The result which I got is :
Error processing transaction: code: 2081 text: PayPal pending payments
are not supported
I am not sure is this issue occurred due to the account problem or the issue due to integration.
Making some research this is a currency issue coming from your sandbox account. I provide you with the answer and putting the source link to investigate further as this was an open ticket.
It looks like your sandbox account is setup to block payments from PayPal accounts with different currencies than the one you're making the request with.
If this is the behavior you want, you will need to create a test customer account with the same currency that you're using with the setup of Drop-in.
If this is not the behavior you want, you can log into sandbox.paypal.com and go to Profile > My Selling Tools > Block Payments to adjust the setting or Profile > My Money > PayPal Balance section > More > Currencies to add the currency of the account you are trying to use.
Source : Paypal sandbox issue
This solved for me:
1) Paypal: in paypal sandbox account I recreated a new Business Account indicating the Country where effectively run application (in my case: IT).
2) Paypal: With the business account just generated, I created new Paypal Application and I get paypal client ID and Secret.
3) Braintree: I re-linked my Paypal Sandbox application indicating credentuals of new Paypal business account: email, Client ID and Client Secret of the application just generated.
4) Into My Application/integration: in my braintree SDK js code (v3) I setted the right currency (in my case EUR) in the paypal setup js code:
<script>
var form = document.querySelector('#checkout-form');
var client_token = "{{ $clientToken }}";
var price = $('#selected_service_price').val();
braintree.dropin.create({
authorization: client_token,
selector: '#bt-dropin',
paypal: {
flow: 'checkout',
amount: price,
currency: 'EUR'
}
}, function (createErr, instance) {
if (createErr) {
console.log('Create Error', createErr);
return;
}
form.addEventListener('submit', function (event) {
event.preventDefault();
instance.requestPaymentMethod(function (err, payload) {
if (err) {
console.log('Request Payment Method Error', err);
return;
}
// Add the nonce to the form and submit
document.querySelector('#nonce').value = payload.nonce;
form.submit();
});
});
});

How to add multiple cards in same customer in stripe payment gateway using php

i was implementing stripe payment in testing mode.Here i got an error like Same token is used again. is there any different way to add multiple cards.
or i need to call retrive function in a separate page so that conflict of same token never come again.And how should i set a card default.
public function createToken($data)
{
$TokenResult=Token::create(array(
"card" => array(
"name" => $data['name'],
"number" => $data['card_number'],
"exp_month" => $data['month'],
"exp_year" => $data['year'],
"cvc" => $data['cvc']
)));
//echo "<pre>";;
//print_r($TokenResult);
$this->token=$TokenResult['id'];//store token id into token variable
$this->chargeCard($this->token); //call chargecard function via passing token id
}
/*
* function to create customer
*/
public function createCustomer($data,$token=null)//pass form data and token id
{
$customer=Customer::create(array(
"email"=>$data['email'],
"description" => $data['name'],
"source" => $token // obtained with Stripe.js
));
$customerId=$customer['id'];
$this->retriveCustomer($customerId,$token);
}
/*
* function to retrive current customers for adding multiple cards to same customers*/
public function retriveCustomer($customerid,$token)
{
echo $this->token;
//die('here');
$retriveResult=Customer::retrieve($customerid);
$retriveResult->sources->create(array("source" =>$this->token));
return $retriveResult;
}
First, please note that unless you are PCI certified and allowed to directly manipulate card data, you should never have access to card numbers in your server-side code.
Card tokens should be created client-side, via Checkout or Elements. Your server should only deal with client-side created card tokens and never with PCI-sensitive information (card numbers and CVCs). This will greatly decrease the burden of PCI compliance and make you eligible for PCI SAQ A.
In PHP, this is how you'd add a card to an existing customer object:
$customer = \Stripe\Customer::retrieve("cus_...");
$card = $customer->sources->create(array(
"source" => $token // token created by Checkout or Elements
));
I think you dont need to create a token in case of adding new card. It helps while you update certain card. So the flow of addition will be same as you created for first card.
I dont know which stripe version you are using, I am using bit old:
$card_array = array(
'card' => array(
'number' => $number,
'exp_month' => $exp_month,
'exp_year' => $exp_year,
'cvc' => $cvc,
'name' => $name
)
);
$card_obj = $this->setData("\Stripe\Customer", "retrieve", $customer_id, TRUE);
$card = $card_obj->sources->create($card_array);
Stripe's docs don't explain a lot of the more nuanced procedures so you have to do a lot of testing.
Assuming you have a customer object $cu, with the token you get from checkout or whatever you use:
$card = $cu->sources->create(['source'=>$token]);
will add a card to the customer. It just adds the card to the list; subsequent calls will add cards to the list. Note that it does not check for duplicates, so the same card can be on the list multiple times. It will also not set the new card to the active card. To make a card the default (or active), use
$cu->default_source = $card
$cu->save();
Using the older card interface:
$cu->card = $token;
$cu->save();
The new card will replace the default card. It will NOT make the previously default card inactive; it will delete the current default and make the new card the active default. The card interface is the easiest if you're just allowing 1 card to be attached to a customer at a time.

Stripe doubles anything

I am using a function I created that I have tried creating customers from, and creating charges from. For whatever reason it seems to be double charging in test mode (Not bringing into live mode under these conditions) and I'm trying to understand why. I had it going through a few functions so I made it all happen in one function to make sure that it had nothing to do with what I had made. I'm lost on why this is happening. I try to make charges from token, doubles in less than a second. I try to create a customer from token, doubles in less than a second. I am using Stripes latest stripe-php library.
public function invoice($invoice = null) {
//Provides billing info for invoice.ctp
$this->loadModel('Invoice');
$billingi = $this->Invoice->get($invoice, [
'contain' => ['Items'],
]);
$dollars = 0;
foreach ($billingi->items as $item) {
$dollars += $item->price;
}
$cents = bcmul($dollars, 100);
$price = floatval($cents);
if ($this->request->is('post')) {
$stripeToken = $this->request->data('stripeToken');
//Sets stripe API
\Stripe\Stripe::setApiKey("sk_test_QVYouMViTf1k3zfVu2VAyZge");
//Retrieves stripe token from stripe API
//$response = \Stripe\Token::retrieve($stripeToken);
\Stripe\Customer::create(array(
"description" => "Test customer",
"source" => $stripeToken // obtained with Stripe.js
));
$this->Flash->success(__('Thank you for your payment!'));
return $this->redirect(['action' => 'approved', $invoice]);
}
/*
if ($response && $this->checkExists($response->card->cvc_check, $response->card->address_zip_check) == true) {
$this->insertCharge($invoice, $response, $price);
} else {
//Throw error because cvc_check or zip came back null (doesn't exist)
}
}
*/
$this->set('billingi', $billingi);
$this->set('_serialize', ['billing']);
}
The reason why there are things commented out is because I wanted to test the function without it, but adding it back later when I understand what the issue is.
In your code, the only API request sent to Stripe is a customer creation request (\Stripe\Customer::create(...)).
This doesn't charge the user -- it merely validates the card from the token in the source parameter, and creates a persistent customer object that you can in turn use to create actual charges. This tutorial explains this flow.
There's nothing in your code that would cause the API request to be sent twice. It's very unlikely the issue is on Stripe's end. More likely, your code is being called twice for some reason that's not related to Stripe. You'd need to add traces to your code to figure out what exactly is being called in what order.

Stripe Laravel not getting some params from Checkout Form

For some reason, some parameters such as amount, and description are not being passed on from the Form to the Controller.
The token is generated and the email is sent too, but not the other params.
In order for the Payment to work I have to enter manually the amount at the controller.
<form action="checkout" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key= "pk_test_zOi8g9ztDo1HNeC6iFFTWqwk"
data-amount="1500"
data-name="Demo Site"
data-description="2 shoes ($20.00)"
data-image="/128x128.png">
</script>
</form>
=====================================
public function PostPaymentData(){
Stripe::setApiKey('sk_test_CvCavCI3G4onNbKxZEaNzkvZ');
// get the data submitted by the CHECK OUT Form
$token = Input::get('stripeToken'); (it gets it)
$amount = Input::get('amount'); (it does not get it)
$description = Input::get('description');(it does not get it)
echo "the amount is . $amount"; //nothing
echo "the description is $description"; // nothing
print_r(input::all()); // it just prints the token and the email
// create the charge on STRIPE servers. This will charge the credit card
try {
$charge = Stripe_Charge::create(array(
"amount" => 1800, // amount in cents, again (I have to enter it manually because $amount = ' ';
"currency" => "usd",
"card" => $token,
"description" => "holycow#gmail.com")
);
}
catch(Stripe_CardError $e) {
// Since it's a decline, Stripe_CardError will be caught
dd($e);
=================================================
Route::get('payments/getpaymentpage', array(
'as'=>'getpaymentpage',
'uses'=>'StripePay#getPaymentPage'
));
Route::post('payments/checkout', array(
'as'=>'checkout',
'uses'=>'StripePay#PostPaymentData'
));
My config for Stripe:
In the providers:
'Abodeo\LaravelStripe\LaravelStripeServiceProvider'
In the composer json
"stripe/stripe-php": "1.*",
"abodeo/laravel-stripe": "dev-master"
Well, it was the support staff from Stripe (very kind people) who has given me the answer:
It's actually expected that the amount doesn't get sent with the token to your server. If it did, the user could easily tamper with it via developer tools or writing javascript snippets, etc. Usually you'll want the price of something to be in your database somewhere (a product or whatever you're selling) and look it up again once you receive the token to get the authoritative price.
But sometimes you've got a situation where the user specifies the price somehow, and that is intentional. In that case I suggest making a hidden form element:
And then populating that with JavaScript using a callback. If you're using Stripe.js you already have a response handler you can use for this, just populate the field before you POST your data. If you're using Stripe Checkout, then you can use the token callback on the handler using the custom integration.

Categories