Stripe sca subscription php and charge automatically - php

I have implemented the Stripe SCA migration
my serve side code to create payment intent is as follows
$intent = \Stripe\PaymentIntent::create([
'payment_method' => $requestData['payment_method_id'],
'amount' => $requestData->amount,
'currency' => $requestData->currencyIso,
'payment_method_types' => ['card'],
'confirmation_method' => "manual",
'confirm' => true,
'setup_future_usage'=>"off_session",
]);
return $intent;
And my js code is as below to create card payment and handle response
stripe.createPaymentMethod('card', cardElement, {
billing_details: {name: cardholderName.value}
})
and handle the response:
function handleServerResponse(response) {
if (response.error) {
} else if (response.requires_action) {
stripe.handleCardAction(
response.payment_intent_client_secret
).then(function(result) {
if (result.error) {
} else {
// The card action has been handled
// The PaymentIntent can be confirmed again on the server
fetch('https://test.com/server.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
payment_method_id: result.paymentMethod.id,
amount: amount
})
}).then(function(confirmResult) {
console.log(confirmResult);
return confirmResult.json();
}).then(handleServerResponse);
}
});
}
}
}
$plan = Plan::create([
'currency' => $currency,
'interval' => 'month',
'product' => $product->id,
'nickname' => 'Payment Plan for order - ' . $order_id,
'amount' => $price,
'metadata' => [
'order_number' => $order_id,
'bgt_customer_number' => $customer_id,
],
]);
$schedule = SubscriptionSchedule::create([
'customer' => $customer->id,
'start_date' => 'now',
'end_behavior' => 'cancel',
'metadata' => [
'local_id' => $order_id,
'local_account_id' => $account_id,
'local_currency_id' => $currency_id,
'local_user_id'=> $user_id,
'local_installments_total' => $plan_length,
'bgt_customer_number' => $customer_id,
'order_number' => $order_id,
'invoice_description' => 'Payment Plan for order - ' . $order_id
],
'phases' => [
[
'items' => [
[
'plan' => $plan->id,
],
],
'collection_method'=> 'charge_automatically',
'iterations'=>$plan_length
],
],
]);
$metadata = [
'installments_paid' => '0',
'installments_total' => $plan_length,
'local_id' =>$order_id,
'local_account_id' =>$account_id,
'local_currency_id' =>$currency_id,
'subscription_schedule_id' => $schedule->id
];
$subscription_id=$schedule->subscription;
$result=Subscription::update($subscription_id,
[
'metadata' => $metadata,
'default_payment_method' => $paymentMethodParams['payment_method'],
'proration_behavior' =>'always_invoice',
//Create only after adding payment method id in customer
]
);
I am getting the SCA modal for sca cards and workflow is correct.
But what concerns me is testing the subscription created using sca
I tested using 4000000000003220 amd also 424242424242424.. and subscription is created with 3 installments.
The subscription is created with correct installments:
But what concerns me is the subscription first installment is not being charged immediately.
Invoice shows as:
This draft invoice was generated by a subscription. It can be edited
until it's automatically finalized in 1 hour.
.
When I try to complete the charge from stripe dashboard (as a part of test) it shows
The invoice was finalized, but the customer needs to complete 3D
Secure authentication for the payment to succeed. This additional
step is required by their bank to prevent fraud. 3D Secure emails are
disabled in your settings, so you'll need to notify the customer
manually
The invoice failed to capture.
Question:
1: I wanted the first installment or schedule to happen.
How do I accomplish this in staging env. Am I missing any points here in creating subscription or SCA methods?
2: What is really 'confirmation_method' => "manual". Really confused.

When using Stripe Subscriptions you typically won't be creating Payment Intents yourself. Instead you'll be creating and interacting with Billing objects like Subscriptions and Invoices. The Invoices will create the Payment Intents for you. Stripe has a guide that walks you through taking payment information and creating a Subscription. If you read through and follow that guide you should be able to build what you want.
To answer your specific questions:
Question: 1: I wanted the first installment or schedule to happen. How do I accomplish this in staging env. Am I missing any points here in creating subscription or SCA methods?
This is likely because you're creating a Payment Intent and paying that which is unrelated to the Payment Intent belonging to the Invoice of your Subscription.
2: What is really 'confirmation_method' => "manual". Really confused.
The confirmation_method property controls how a Payment Intent can be confirmed. However, if you're using Subscriptions and want to support SCA you should ignore this property and instead follow the guide linked above.

Related

Stripe : No card attached to customer after a checkout session payment

I'm using Stripe with PHP, I want to create subscription to customer after a payment made with Stripe Checkout Session.
But, the problem is that when we do a one shot payment with Stripe Checkout Session, Stripe does not attach the source (Credit card) to the customer, and when I try to subscribe this customer to a plan, Stripe return me the error :
This customer has no attached payment source or default payment method.
I don't understand why Stripe don't attach the card to the customer with one shot payment because Stripe do it when we use a Checkout Session with Subscription.
How I create checkout session :
$checkout_session = Session::create([
'payment_method_types' => ['card'],
'mode' => 'payment',
'customer' => 'cus_xxxxxxxx',
'line_items' => [[
'price' => 'price_xxxxx', // Oneshot payment
'quantity' => 1,
]]
]);
How I try to subscribe customer (After successful payment) :
$subscription = Subscription::create([
'customer' => 'cus_xxxxxxxx',
'items' => [
['price' => 'price_XXXXXXX'] // Recurrent payment
],
'trial_from_plan' => true,
]);
Thank you for your help
When accepting a one-time payment with Checkout, it won't create a Customer or save card details by default. What you have to do is configure Checkout to do this for you during the payment. This is covered in their documentation here.
What you need to do is set the payment_intent_data[setup_future_usage] parameter like this:
$checkout_session = Session::create([
'payment_method_types' => ['card'],
'mode' => 'payment',
'customer' => 'cus_xxxxxxxx',
'line_items' => [[
'price' => 'price_xxxxx', // Oneshot payment
'quantity' => 1,
]],
'payment_intent_data' => [
'setup_future_usage' => 'off_session',
]
]);
After that, you will have a Customer cus_123 and a PaymentMethod pm_123 that you can re-use. That PaymentMethod will not be the default one though so you need to make sure that you pass its id in the default_payment_method parameter when you create the Subscription like this:
$subscription = Subscription::create([
'customer' => 'cus_xxxxxxxx',
'items' => [
['price' => 'price_XXXXXXX'] // Recurrent payment
],
'trial_from_plan' => true,
'default_payment_method' => 'pm_12345',
]);
Also note that you can start a Subscription directly from Checkout as documented here.

Stripe Create Invoice and auto charge

I am creating an invoice and auto charging a customer via their PHP package. The issue is though the invoice is created but the card on file is not charged, it says fail. This is odd to me because if I go into the dashboard online, find the invoice the is listed as "failed" and manually click the "retry charge" it works. Why would this be? Its clearly creating the invoice correctly and trying to charge the card on file but the card seems to only clear on ALL of these invoices if I go in and manually retry the charge.
$stripe = new \Stripe\StripeClient(config('XXXXXXXXXXXXXXXXX'));
$item = $stripe->invoiceItems->create([
'customer' => $subscription->stripe_customer,
'amount' => $total,
'currency' => 'usd',
'description' => 'Erro Coffee Subscription ' . $subscription_type->bags
]);
$invoice = $stripe->invoices->create([
'customer' => $subscription->stripe_customer,
'collection_method' => 'charge_automatically',
'auto_advance' => true,
"metadata" => [
"order_type" => "subscription",
"subscription_refill" => "true",
"subscription_id" => $subscription->id
]
]);

Trying to charge before or after Subscription Schedule is created Stripe API

I am developing a wordpress website for a client.
He needs different types of packages. For most of these packages I developed a simple Stripe checkout webpage, using its documentation.
The problem is that I need this workflow:
first month x dollars
second month x dollars
after one year subscription y dollars
I've already done this using Subscription Schedule. But it needs a customer ofc. How can I charge before and after charging create this Subscription Schedule? I don't know how to deal with this, how to charge using Stripe checkout simple already built page or do I need to create one by myself, where user needs to add his card, pay, and get the customer_id?
function checkout3() {
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
\Stripe\Stripe::setApiKey('sk_test_51e7DRPLRnISGb5vSFxnvvuDx1GzhlBIFeazcmpEevsUFf29jHXJ1YgE2xaJ1lGfzjtKzE8uoN0eR9Klaq00CnMFWvfB');
// The price ID passed from the front end.
// $priceId = $_POST['priceId'];
$priceId = 'price_1LPahmIne7DRPLRnFXV6Uz34';
$futureDate= strtotime(date('Y-m-d', strtotime('+1 year')));
$customer = \Stripe\Customer::create(
[
'description' => 'My First Test Customer (created for API docs at https://www.stripe.com/docs/api)',
]
);
$session = \Stripe\SubscriptionSchedule::create([
'customer' => $customer["id"],
'start_date' => 'now',
'end_behavior' => 'release',
'phases' => [
[
'items' => [
[
'price' => 'price_1LRF5CIne7DRPLRnwuLVE2pu',
'quantity' => 1,
],
],
//'end_date' => $futureDate,
'iterations' => 1,
],
[
'items' => [
[
'price' => 'price_1LRF5cIne7DRPLRngevvIZiw',
'quantity' => 1,
],
],
'iterations' => 1,
],
[
'items' => [
[
'price' => 'price_1LPujQIne7DRPLRnj3EOweJN',
'quantity' => 1,
],
],
],
],
]);
// Redirect to the URL returned on the Checkout Session.
// With vanilla PHP, you can redirect with:
//header("HTTP/1.1 303 See Other");
//header("Location: " . '$session->url');
}
So right now, the subscription schedule is added to the Stripe dashboard, the page it's keep loading infinitely, but without charging... How to deal with this?
public static function firebase_checkout3_func() {
$html = "";
$html .= "<form id='firebase-checkout' action='/wp-json/api/checkout2' method='POST'>
<button type='submit' id='checkout-button'>Începe acum</button>
</form>";
return $html;
}
Use Stripe hosted Checkout Page with setup mode to collect
a Customer's SetupIntent
Retrieve the Payment Method inside the SetupIntent
Set it as the customer's invoice_settings.default_payment_method
Create a Subscription Schedule with that Customer Id as normal

How to authorize with Stripe 3d Secure while Subscription type is Trailing

I want the 3d-secure modal authorization check with subscription type = trialing.
I am following this link to setup stripe subscription. When I create subscription without 'trial_period_days' the 3d-secure authorization modal pops-up as subscription status becomes 'incomplete'.
But when i pass >trial_period_days and 'payment_behavior' => 'allow_incomplete', modal don't work as subscription status becomes 'active'.
How can i show authorization modal when subscription is trialing?
I have seen this link https://stripe.com/docs/payments/3d-secure#manual-three-ds too, but no progress.
Suggest me a way to implement this.
Here is my code:
public function createCustomer($token) {
\Stripe\Stripe::setApiKey(secretKey);
$customer = \Stripe\Customer::create([
'email' => 'any_email#domain.com',
'source' => $token,
]);
return $this->createSubscription($customer, $token);
}
public function createSubscription($customer, $token) {
$plan_id = $this->getPlanId();
$payment_intent = $this->createSetupIntent($customer->id, $token);
$subscription = \Stripe\Subscription::create([
'customer' => $customer->id,
'items' => [
[
'plan' => $plan->id,
],
],
'trial_period_days' => 14,
'expand' => ['latest_invoice.payment_intent'],
'payment_behavior' => 'allow_incomplete',
]);
return [
'subscription' => $subscription,
'payment_intent' => $payment_intent
];
}
public function createSetupIntent($customer_id, $token) {
$client = new Client();
$url = "https://api.stripe.com/v1/setup_intents";
$response = $client->request('POST', $url, [
'auth' => ['sk_test_key', ''],
'form_params' => [
'customer' => $customer_id,
'payment_method_types' => ["card"],
'payment_method_options' => [
"card" => [
"request_three_d_secure" => "any"
]
]
],
'timeout' => 10.0
]);
$setup_intent = $response->getBody()->getContents();
return json_decode($setup_intent, true);
}
I expect 3d-secure authorization check modal too when i set subscription to trialing.
What you are describing is a scenario in Stripe doc
Basically when you create a subscription with trial period, since there is no immediate payment occurs, there will be no 3DS authentication needed.
The authentication is delayed until the trial period end.
To ask the user for authentication so that when the trial end there will be no need for 3DS authentication, when a subscription is created with trial period, The subscription will have a pending_setup_intent attribute
You could use that pending_setup_intent to ask the user to complete the authentication. You don't have to create a setup Intent explicitly. What you can do is to check the status within the subscription.
If subscription is in trialing, check if there is a pending_setup_intent, if so, pass to the pending_setup_intent.client_secret to the frontend where your customer is subscribing to your product, and call Stripe.js handleCardSetup
stripe.handleCardSetup(psi.client_secret)
.then(siResult => {
log({siResult});
}).catch(err => {
log({siErr: err});
});
When the card is setup and the trial ends, there will be less likely that the charge will need to go through 3DS authentication again.
You could use Stripe Test Card, 4000002500003155 is good for this testing.
You could simulate the trial end by updating the subscription with
trial_end: "now"
off_session: true // This is needed because by default, subscription update is considered on_session
Hope the above helps

Amount must be greater than zero, PayPal/Braintree payment

I have an app that sells events, some events have zero-dollar price. Thus, I receive this message from PayPal:
Amount must be greater than zero
However, if I remove the need to make a payment, one user can order all the tickets for an event. So, what's the way to make users go through the payment process without making a charge.
Bear in mind, it'd be great to make as little change to the process in terms of generating a Nonce from frontend and sending it to backend to make the charge it.
I'm using this payment scenario.
This is the function that returns the error message:
public function chargeNonce($nonce) {
$gateway = $this->createPayPalGateway();
$amount = $this->payment_params['number_of_tickets'] * $this->payment_params['event_price'];
$result = $gateway->transaction()->sale([
'amount' => $amount,
'paymentMethodNonce' => $nonce,
'options' => [
'submitForSettlement' => True,
'paypal' => [
'description' => "Billing Notification",// For email receipt
],
],
]);
dd($result);
return $result;
}

Categories