Integration of CCAvenue Payment Gateway with Angular Firebase

Angular Component, Angular Service and Two Cloud Functions

Ccavenue is a great payment provider and as a developer, you shall soon run into a scenario, requiring you to integrate ccavenue payment to your existing Angular Firebase Application.

I spent a bit of time figuring it out using all the help available on the net.

Here is how you do this integration. My example is for the Non-Seamless option offered by ccavenue.

You will need to add two Cloud Functions.

One function will be used to encrypt the data before sending it.

The other function will handle the response from ccavenue.

We will also create an Angular component to post the data, and a service to call the cloud function for encryption, before we post the data to ccavenue.

Before I dive into the code, I would like to share two links which have helped me in understanding the integration process.

  1. This is an article by Dave on the process. We will also be using the component node-ccavenue made by him in our cloud functions.

  2. Ccavenue payment integration with Angular7 Nodejs and loopback written by Divya Chandana. I have used some of the bits from her code.

Let us dive into the code:

Angular Component TS File

import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
import { EncryptDecryptService } from 'src/app/services/encrypt-decrypt.service';

@Component({
  selector: 'app-payment-make',
  templateUrl: './payment-make.component.html',
  styleUrls: ['./payment-make.component.scss']
})
export class PaymentMakeComponent implements OnInit {
  @ViewChild('form', {static: false}) form: ElementRef;
  public accessCode: any;
  public encRequestRes : any;
  public orderObj: any;
  constructor(
    private encryptDecryptService: EncryptDecryptService,
  ) { }

  ngOnInit(): void {
    this.accessCode = 'YOUR_ACCESS_CODE';
    this.initOrderObj();
  }

  initOrderObj() {
    const encodedRedirectUrl = encodeURIComponent(`https://your-domain.cloudfunctions.net/handleccavenueresponse/`);
    this.orderObj = {
      merchant_id: 999999,  //replace with your merchant id
      order_id: 'some_order_id',
      currency: 'INR',
      amount: 1000,  // change amount if required
      redirect_url: encodedRedirectUrl,
      cancel_url: encodedRedirectUrl,
      language: 'EN',
      billing_name: 'Somil Mittal',
      billing_address: '33 Wood Street',
      billing_city: 'Bengaluru',
      billing_state: 'Karnataka',
      billing_zip: '560020',
      billing_country: 'India',
      billing_tel: '3384747557',
      delivery_name: 'Somil Mittal',
      delivery_address: '33 Wood Street',
      delivery_city: 'Bengaluru',
      delivery_state: 'Karnataka',
      delivery_zip: '560020',
      delivery_country: 'India',
      delivery_tel: '3384747557',
      billing_email: 'somilmittal@gmail.com'
    };
    console.log('order object----------', this.orderObj);
  }

  checkout(){
    this.encryptDecryptService.encryptCcavenueOrder(this.orderObj).subscribe(data => {
      console.log('encryted order---------------------', data)
      this.encRequestRes = data;
          setTimeout(()=>{
              this.form.nativeElement.submit();
          },1000)
      }, error => {
      console.log(error)
      }
    );
  }

}

Angular Component html file

<h3>Click Here! to go CCAvenue</h3>
<button (click)="checkout()">Checkout Payment Gateway</button>

<form #form ngNoForm
  id="nonseamless"
  method="post"
  name="redirect"
  action="https://test.ccavenue.com/transaction/transaction.do?command=initiateTransaction">
    <input type="hidden" id="encRequest" name="encRequest" value="{{encRequestRes}}">
    <input type="hidden" name="access_code" id="access_code" value="{{accessCode}}">
</form>

Make a note of the ngNoForm used in the code above. This is important for the form to be submitted to ccavenue.

Angular Service to call the cloud function

import { Injectable } from '@angular/core';
import { AngularFireFunctions } from '@angular/fire/functions';
import { Observable } from 'rxjs/observable';

@Injectable({
  providedIn: 'root'
})
export class EncryptDecryptService {
  constructor(
    private fns: AngularFireFunctions
  ) { }

  encryptCcavenueOrder(orderParams: any): Observable<any> {
    const encryptOrderTest = this.fns.httpsCallable('encryptOrder');
    return encryptOrderTest(orderParams);
  }
}

Notice, I am using the AngularFireFunctions package to call the Cloud Function.

Now, lets us go node side, and add two cloud functions.

Here is the index.js file (which will live inside the functions folder)

const functions = require("firebase-functions");

const admin = require("firebase-admin");
admin.initializeApp(functions.config().firebase);

const cors = require('cors')({ origin: true });

const nodeCCAvenue = require('node-ccavenue');
const ccav = new nodeCCAvenue.Configure({
  merchant_id: 999999, // replace with your merchand id
  working_key: 'PUT_YOUR_WORKING_KEY_HERE'
});

//cloud function to handle the response from ccavenue
exports.handleccavenueresponse = functions.https.onRequest((req, res) => {
  const { encResp } = req.body;
  const output = ccav.redirectResponseToJson(encResp);
  // The 'output' variable is the CCAvenue Response in JSON Format
  console.log(output);
  const orderId = output.order_id;
  console.log('ORDER_ID IS ---------', orderId);

  //Store the returned object in your realtime database
  admin.database().ref(`/orders/${orderId}/`).set(output);

  if(output.order_status === 'Failure') {
     // DO YOUR STUFF
    res.writeHead(301,
      {Location: 'https://your-domain.com/payment-bad'}
    );
    res.end();
  } else if (output.order_status === 'Success') {
    // DO YOUR STUFF
    res.writeHead(301,
      {Location: 'https://your-domain.com/payment-good'}
    );
    res.end();
    }
  });

  //cloud function to encrypt the data before posting to ccavenue
  exports.encryptOrder = functions.region('us-central1').https.onCall(async (data, context) => {
    const encryptedOrderData = ccav.getEncryptedOrder(data);
    console.log('data passed is', data);
    console.log(encryptedOrderData);

    return encryptedOrderData;
  });

Most of the heavy lifting is done by the npm node-ccavenue package. Here is the direct link to the package for those interested in further details:

Upon payment success or failure, the code is redirecting to two angular pages. Make sure you add them to your application.

I hope this post helps you understand the ccavenue integration, and saves time.