Angular 11 Stripe Custom Checkout With Laravel 8

18 May, 2021 5 minute read

Angular 11 Stripe custom checkout With Laravel 8

Summary

Integrate Stripe payment gateway custom checkout with latest API (v3). Without using any third-party packages, You just need a stripe API key and create an API. We are using Laravel to store payment information and all the details regarding payment.

Step 1:  Include the latest version of API and API key In the ‘index.html’ file on the root location

<script src="https://js.stripe.com/v3/"></script>

<script type="text/javascript">

 var stripe = Stripe('pk_test_Cm9ePTiRuBiSkbP8G3U8BNLR00wgT1ZB6Q'); // use your publishable key

</script>

Step 2: Crate Billing service

File location: src/app/_services/billing.service.ts


import { Injectable} from '@angular/core';
import {Subject} from "rxjs";
import { HttpClient } from '@angular/common/http';
declare var Stripe: any;



@Injectable({ providedIn: 'root' })
export class BillingService{

  private cardDtl: Subject = new Subject();
  getCardDetails$ = this.cardDtl.asObservable();

 constructor(private http: HttpClient ) { }

// init payment form with all the input fields

 initPaymentForm(paymentForm: any){

   const stripe = (window as any).stripe;
   var elements = stripe.elements();
   const style = {
     base: {
       color: '#fff',
       fontWeight: 500,
       fontSize: '18px',
       lineHeight: '30px',
       padding: '40px',
       fontSmoothing: 'antialiased',
       ':-webkit-autofill': {
         color: '#fce883',
       },
       '::placeholder': {
         color: 'rgba(224, 176, 156, 0.4)',
       },
     }
   };

   paymentForm.value.card_number = elements.create('cardNumber', {
     placeholder: "9876  5432  0123  4567",
     style: style
   });

   let cardExpiry = elements.create('cardExpiry', {
     placeholder: "MM / YY",
     style: style
   });

   let cardCVC = elements.create('cardCvc', {
     placeholder: "CVV",
     style: style
   });

   paymentForm.value.card_number.on('change', (e: any) => {
     this.cardDtl.next(e);
   });
   cardExpiry.on('change', (e: any) => {
     this.cardDtl.next(e);
   });
   cardCVC.on('change', (e: any) => {
     this.cardDtl.next(e);
   });

   paymentForm.value.card_number.mount('#cardNumber');
   cardExpiry.mount('#cardExpiry');
   cardCVC.mount('#cardCVC');
 }

// Confirm card step up, is the card is valid or not validate by Stripe

 confirmCardSetup(intent: any, paymentForm: any, cb: any){
   const stripe = (window as any).stripe;
 return   stripe.confirmCardSetup(intent.client_secret, {
     payment_method: {
       card: paymentForm.value.card_number,
       billing_details: {
         name: 'Vikas Singh',
         address: {
           city: 'Noida',
           country: 'IN',
           line1: xxxx Delhi',
           postal_code: '110000',
           state: 'Delhi',
         }
       },
     },
   }) .then(cb);
 }

// This method is for handle 3d secure authentication

 handleConfirmCardPayment(intent: any, cb: any){
     const stripe = (window as any).stripe;
  return  stripe.confirmCardPayment(intent.client_secret, {
       payment_method: intent.payment_method
     }).then(cb, this);

 }

}


Step 3: Create payment component where you call Billing service


import {Component, Output, EventEmitter, Input, SimpleChange} from '@angular/core';
import {environment} from "../../../../environments/environment";
import {HttpClient} from "@angular/common/http";
import {ActivatedRoute, Router} from "@angular/router";
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
import {BillingService} from "../../../_services/billing.service";

@Component({
 selector: 'payment',
 templateUrl: './payment.component.html',
 styleUrls: ['./payment.component.scss']
})

export class PaymentComponent {


    cardDetails: any;
   cardError: any;
   cardBrand: any = 'general_card';
   addCardForm: any = FormGroup;
   intent: any;
   captureData: any;

 constructor(
   private fb: FormBuilder,
   private httpClient: HttpClient,
   private route: ActivatedRoute,
   private router: Router,
   private billing: BillingService,

 ) {

    // Here you can get details of card like brand, error and all

     this.billing.getCardDetails$.subscribe((value: any) => {
         this.cardError = value.error? value.error.message:'';
         this.cardError?this.notifyService.showError(this.cardError):
             this.cardDetails = value;
         this.cardBrand = value.brand?value.brand: 'general_card'
     });
 }

 ngOnInit(): void {
     this.addCardForm = this.fb.group({
         card_number: [''”],
         expDate: [''”]],
         cvv: [“”],
     });
 }
 ngAfterViewInit(): void {
     this.billing.initPaymentForm(this.addCardForm)
 }


   submitPay() {
       this.btnLoader = true;
       if(this.cardError != ''){
           this.btnLoader = false;
           return;
       }
       this.httpClient.get(environment.apiUrl + '/add-card-intent').subscribe(data => {
               this.intent = data;
               if (this.intent.success) {
                   this.intent = this.intent.data;
                   this.intent = this.intent.intent;
                   this.payConfirmCardSetup()
               }
           },
           err => {
               this.btnLoader = false;
               this.notifyService.showError(err.message)
           },
           () => {

           }
       )
   }

   payConfirmCardSetup() {
       this.btnLoader = true;
       this.billing.confirmCardSetup(this.intent, this.addCardForm, (response: any) => {
           if ( response.error ) {
             // You can show the error		
            //   this.notifyService.showError(response.error.message);
            //   this.btnLoader = false;
           } else {
               this.capturePayment(response.setupIntent)
           }
       });
   }

   capturePayment(result: any){
  //     this.btnLoader = true;
       this.httpClient.post(environment.apiUrl + '/capture-payment', {
           payment_method: result.payment_method,
       }).subscribe(data => {
               // @ts-ignore
	// this is success section, you can write the success action 
this.captureData = data;
this.captureData = this.captureData.data;

if (this.captureData.success) {
   this.captureData = this.captureData.intent;
}else{
 // this is section for verify 3d secure process
   if ( this.captureData.status === 'requires_action' ) {
       this.handleConfirmCardPaymentResponse( this.captureData );
   }

           },
           err => {

            // This is error section, you can show the error to user		
             //  this.btnLoader = false;
             //  this.notifyService.showError(err.message)
           },
           () => {
             //  this.btnLoader = false;
           }
       )
   }
  }


handleConfirmCardPaymentResponse(result: any){
   this.billing.handleConfirmCardPayment(result, (response: any) => {
       if ( response.error ) {
        //   this.notifyService.showError(response.error.message);
          //  this.btnLoader = false;
       } else {
           if ( response.paymentIntent.status == "succeeded" ) {

               this.httpClient.post(environment.apiUrl + '/confirm-payment', response.paymentIntent).subscribe((data: any) => {
                       this.confirmData = data;
                       if (this.confirmData.success) {
                       //    this.closeTopup.emit("false");
                         //  this.refreshList.emit("true");
                          // this.sharedService.setValue(this.confirmData.data.ic);
                       }
                   },
                   (err: any) => {
                 //      this.btnLoader = false;
                   //    this.notifyService.showError(err.message)
                   },
                   () => {
                      // this.btnLoader = false;
                   }
               )
           }
       }
   });
}

Step 4: Create payment.component.html and put all the UI of the Payment form

   <form [formGroup]="addCardForm" (ngSubmit)="submitPay()">

                   <div class="addAccountForm">

                       <div class="form-group card-no-rightModal">

                           <label class="form-group-label">Card number</label>

                           <div class="RightcardNoSec">

                               <div id="cardNumber" class="{{((cardDetails?.elementType == 'cardNumber' && cardError)?'invalid-input':'')}}"></div>

<!--                                Here you can show the card brand -->


                               <img src="../angular/assets/images/{{cardBrand}}.svg" class="rightMdoalCardImg">

                            </div>

                       </div>

                       <div class="form-group">

                           <label class="form-group-label">Card holder’s name</label>

                           <input type="text" class="form-group-input darkinput"

                                  placeholder="enter card holder’s name">

                       </div>

                       <div class="multi-form-group">

                           <div class="form-group">

                               <label class="form-group-label">Exp date</label>

                               <div id="cardExpiry" class="card-expiry {{((cardDetails?.elementType == 'cardExpiry' && cardError)?'invalid-input':'')}}"></div>

                           </div>

                           <div class="form-group">

                               <label class="form-group-label">CVV

                                  

                               </label>

                               <div id="cardCVC" class="{{((cardDetails?.elementType == 'cardCvc' && cardError)?'invalid-input':'')}}"></div>

                           </div>

                       </div>

                       <button class="primary-btn-lg" [disabled]="cardError || btnLoader">Pay <span [ngClass]="{'btn-loader': btnLoader}"></span></button>

                   </div>

               </form>

Step 4: Create API for payment


a. Create routes

Route::get('add-card-intent', 'StripeController@setupIntent');
Route::post('capture-payment', 'StripeController@capturePayment');
Route::post('confirm-payment', 'StripeController@confirmPayment');


b. Create Stripe controller add methods


public function setupIntent(Request $request){
   try {
       $user = $request->user();
       $intent = $user->createSetupIntent();
       $response = ['success' => true, 'intent' => $intent];
      return response()->json($response, 200);

   }
   catch (Exception $e){

return response()->json($e->getMessage(), 200);

   }
}


public function capturePayment(Request $request){
try {

$user = $request->user();
$paymentMethod = $request->payment_method;

$payableAmount = (int)100 * $amount;
$payment = $user->charge($payableAmount, $paymentMethod);

 if (isset($payment)) {
   return response()->json(‘'Payment successfully.'’, 200);

}else{
   return response()->json('Your payment is not deduct, Something went wrong.', [], 200);
}

}

catch (IncompletePayment $ex) {
   $intent = $ex->payment->asStripePaymentIntent();
   if ($ex instanceof \Laravel\Cashier\Exceptions\PaymentActionRequired) {
       return response()->json(['success' =>  false,
           'user_id'  =>  $user->id,
           'status'  =>  $intent->status,
           'client_secret'  =>  $intent->client_secret,
           'payment_method'  =>  $intent->payment_method,]);
   } else {
       return response()->json($ex->getMessage(),[] , 400);
   }
}
catch (Exception $e){
   return response()->json($e->getMessage(),[], 400);
}
}
Shobhit Singh

Shobhit Singh

Lead Developer at Signifier Technology Pvt Ltd

Leave a Reply

More from Rannkly

Our best blog on PHP

PHP

Integrate CCavenue Payment Gateway In PH...

Shobhit Singh

Shobhit Singh

10 minute read

Integrating CCAvenue with php web application

Read more
PHP

PHP Latitude Longitude To Address

Vishnu Sharma

Vishnu Sharma

1 minute read

Read more

Laravel Latest Version 5.7 With Material...

Stuti varshney

Stuti varshney

1 minute read

Read more