Laravel What to Add to Users Table if Im Only Doing One Off Payments Cashier
Payments are one of the most typical elements of whatsoever web-project, and Stripe is a payment provider that is really like shooting fish in a barrel to install in Laravel projects. In this article, we volition add a payment course to the page.
Equally an case, we volition accept a Production Show page from our QuickAdminPanel Product Management module, merely yous can follow the same instructions and add together Stripe course to ANY Laravel project page.
The plan will consist of 8 steps:
- Install Laravel Cashier
- Run Cashier migrations
- Stripe Credentials in .env
- User Model should be Billable
- Controller: Form Payment Intent
- Blade Page: Class, Styles, and Scripts
- Controller: Post Payment Processing
- After Successful Purchase: Send Production
Let's begin!
i. Install Laravel Cashier
Run this control:
composer require laravel/cashier
Detect: Currently, the latest version of Cashier is v12. If you're reading this article when the newer version has arrived, please read its upgrade guide. Merely personally, I incertitude that any fundamentals will change.
2. Run Cashier migrations
Cashier package registers its own database migration directory, so remember to migrate your database subsequently installing the package:
php artisan migrate
Those migrations are non in database/migrations folder, they are inside /vendor. Hither are the contents.
i. Iv new columns to users table:
Schema::tabular array('users', function (Pattern $table) { $tabular array->string('stripe_id')->nullable()->index(); $tabular array->string('card_brand')->nullable(); $table->string('card_last_four', 4)->nullable(); $table->timestamp('trial_ends_at')->nullable(); }); 2. New table subscriptions:
Schema::create('subscriptions', office (Blueprint $table) { $tabular array->bigIncrements('id'); $tabular array->unsignedBigInteger('user_id'); $table->cord('name'); $table->string('stripe_id'); $table->string('stripe_status'); $table->string('stripe_plan')->nullable(); $table->integer('quantity')->nullable(); $table->timestamp('trial_ends_at')->nullable(); $table->timestamp('ends_at')->nullable(); $tabular array->timestamps(); $table->index(['user_id', 'stripe_status']); }); 3. New table subscription_items:
Schema::create('subscription_items', function (Blueprint $tabular array) { $table->bigIncrements('id'); $tabular array->unsignedBigInteger('subscription_id'); $tabular array->cord('stripe_id')->index(); $tabular array->string('stripe_plan'); $table->integer('quantity'); $table->timestamps(); $table->unique(['subscription_id', 'stripe_plan']); }); 3. Stripe Credentials in .env
There are two Stripe credentials that you lot need to add together in your .env file:
STRIPE_KEY=pk_test_xxxxxxxxx STRIPE_SECRET=sk_test_xxxxxxxxx
Where to get those "key" and "secret"? In your Stripe Dashboard:
Keep in mind, there are two "modes" of Stripe keys: testing and live keys. While on your local or testing servers, please remember to apply TESTING keys, you lot can view them by toggling "View Testing Data" on the left menu:
Another style to know if you're using testing/live keys: the testing keys beginning with sk_test_ and pk_test_, and alive keys start with sk_live_ and pk_live_. Also, live keys won't work without SSL certificate enabled.
Notice: if y'all work in a squad, when you add new variables, it'due south a very good practice to also add them with empty values in .env.example. Then your teammates volition know what variables are needed on their server. Read more here.
4. User Model should be Billable
Simple step: in your User model, add Billable trait from Cashier:
app/Models/User.php:
// ... use Laravel\Cashier\Billable; class User extends Authenticatable { use HasFactory, Billable; 5. Controller: Form Payment Intent
To enable the Stripe payment form, we need to create a thing called "payment intent" and pass it to the Bract.
In this case, we will add it to ProductController method show():
class ProductController extends Controller { // ... public part show(Product $product) { $intent = auth()->user()->createSetupIntent(); return view('frontend.coupons.show', compact('product', 'intent')); } Method createSetupIntent() comes from the Billable trait that we added just above in User model.
half-dozen. Blade Page: Form, Styles, and Scripts
This is the class that we will add from Stripe, with cardholder name, card number, decease month/yr, CVV code, and Goose egg code.
Luckily, Stripe documentation tells united states of america exactly what HTML/JavaScript/CSS code should exist added.
So, in our show.blade.php, we add this:
<grade method="Post" activity="{{ route('products.purchase', $product->id) }}" class="card-grade mt-three mb-3"> @csrf <input blazon="subconscious" name="payment_method" class="payment-method"> <input course="StripeElement mb-3" proper name="card_holder_name" placeholder="Card holder proper noun" required> <div form="col-lg-4 col-md-6"> <div id="card-element"></div> </div> <div id="card-errors" role="alert"></div> <div class="class-grouping mt-three"> <push type="submit" course="btn btn-chief pay"> Buy </push> </div> </form> All the input variables are exactly as Stripe suggests information technology, the only element that you would need to change is the route, where the class would be posted, so this:
road('products.purchase', $production->id) Nosotros will create that route and Controller method in the next step.
Meanwhile, we besides need to include Stripe's Styles and JavaScript.
Allow's imagine that in your primary Blade file, you have @yield sections for styles and scripts, like this:
<!DOCTYPE html> <html> <caput> ... @yield('styles') </head> <body> ... @yield('scripts') </body> </html> And then, in our show.blade.php, nosotros may fill in those sections, with code from Stripe:
@section('styles') <style> .StripeElement { box-sizing: border-box; height: 40px; padding: 10px 12px; border: 1px solid transparent; border-radius: 4px; background-colour: white; box-shadow: 0 1px 3px 0 #e6ebf1; -webkit-transition: box-shadow 150ms ease; transition: box-shadow 150ms ease; } .StripeElement--focus { box-shadow: 0 1px 3px 0 #cfd7df; } .StripeElement--invalid { border-color: #fa755a; } .StripeElement--webkit-autofill { background-color: #fefde5 !of import; } </mode> @endsection @section('scripts') <script src="https://js.stripe.com/v3/"></script> <script> let stripe = Stripe("{{ env('STRIPE_KEY') }}") allow elements = stripe.elements() allow style = { base: { colour: '#32325d', fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#fa755a', iconColor: '#fa755a' } } let carte du jour = elements.create('card', {style: way}) card.mount('#carte du jour-element') let paymentMethod = aught $('.card-form').on('submit', function (e) { $('push.pay').attr('disabled', true) if (paymentMethod) { render true } stripe.confirmCardSetup( "{{ $intent->client_secret }}", { payment_method: { carte du jour: carte, billing_details: {proper noun: $('.card_holder_name').val()} } } ).then(function (result) { if (issue.error) { $('#card-errors').text(outcome.fault.bulletin) $('button.pay').removeAttr('disabled') } else { paymentMethod = result.setupIntent.payment_method $('.payment-method').val(paymentMethod) $('.card-form').submit() } }) return false }) </script> Inside of those sections, we're calculation 2 variables from the back-finish:
env('STRIPE_KEY') and
$intent->client_secret
So make sure you added them in the previous steps.
7. Controller: Post Payment Processing
Call up the route that we called in the previous step? Fourth dimension to create information technology.
In routes/spider web.php, add together this:
Route::post('products/{id}/purchase', 'ProductController@buy')->name('products.purchase'); And so, let's create a method in ProductController:
public function purchase(Request $request, Product $product) { $user = $request->user(); $paymentMethod = $request->input('payment_method'); endeavor { $user->createOrGetStripeCustomer(); $user->updateDefaultPaymentMethod($paymentMethod); $user->accuse($product->price * 100, $paymentMethod); } catch (\Exception $exception) { return back()->with('error', $exception->getMessage()); } return dorsum()->with('message', 'Production purchased successfully!'); } So what is happening here?
1. We're getting payment_method from the class (Stripe handles it in the background for us)
ii. And so we call the Cashier methods to get/create the customer, set up their payment method, and charge them.
iii. Finally, we redirect dorsum with success consequence
3b. If something goes wrong, try/catch cake handles it and redirects back with an error.
Discover: variable $product->price is the price for your product, and nosotros demand to multiply it by 100 considering Stripe charge is happening in cents.
To show the success bulletin or errors, in your Bract file, yous demand to add together something like this:
@if(session('message')) <div form="alert warning-success" role="alert">{{ session('message') }}</div> @endif @if(session('error')) <div class="alert warning-danger" role="alarm">{{ session('mistake') }}</div> @endif 8. Subsequently Successful Purchase: Ship Product
Afterwards the customer paid for the product, yous need to deliver the order. Of course, it depends on what they purchased and that code is very individual, merely I will show yous where to put it.
In fact, there are two ways. Easier simply less secure, or harder and more secure.
Option 1. Fulfill Order in ProductController
You can do that directly in the same method:
public function purchase(Request $request, Product $product) { $user = $asking->user(); $paymentMethod = $request->input('payment_method'); effort { $user->createOrGetStripeCustomer(); $user->updateDefaultPaymentMethod($paymentMethod); $user->charge($product->price * 100, $paymentMethod); } catch (\Exception $exception) { return back()->with('error', $exception->getMessage()); } // Here, complete the order, like, send a notification electronic mail $user->notify(new OrderProcessed($product)); return back()->with('message', 'Product purchased successfully!'); } Easy, correct? The problem with that method is that it'southward happening in sync, which ways that $user->accuse() may non be really successfully finished, by the time you lot fulfill the order. In theory, it may crusade fake order deliveries with unsuccessful charges.
Selection 2. Stripe Webhooks
Or, a more than reliable method, is to take hold of so-called Stripe Webhooks. They ensure that the charge happened successfully, in the right fashion. Whenever something happens in Stripe, they ship a POST asking to your server'south URL that you provide in the Stripe dashboard.
Y'all can catch a lot of events from Stripe, and one of those events is charge.succeeded.
For that, I would recommend using a package called Laravel Stripe Webhooks, I've shot a separate video about information technology:
And then if you want to catch more than events, and non but charge success, I suggest you to use Stripe Webhooks. Continue in listen they won't (easily) work on your local computer, you need to set up a existent domain that Stripe would call.
That's it! Wish yous to receive a lot of successful payments in your projects.
Source: https://blog.quickadminpanel.com/how-to-add-stripe-one-time-payment-form-to-laravel-project/
0 Response to "Laravel What to Add to Users Table if Im Only Doing One Off Payments Cashier"
Post a Comment