How To Resolve UPI Getaway In Intent View Error On Js Code Kolkata Fatafat
Tags: php, json, javascript, androiddev
Published: 2024-03-06 18:53:53

**First of all let us see one of our php website for demo.**
https://kolkataff.win/upi-getway/

Our domain is this
https://kolkataff.win/

Now let us move towards the code. After doing a lot of research we have found a solution for it. Please do give us a review.

First of all we use UPI intent on browser to make UPI transaction insecure so we can easily secure our transaction by using JS or by using phonepe package name or by using merchant UPI.

/
[..]
/
UPI Intent
/
How to create a dynamic QR on Web?

UPI Intent
The API can be used for providing intent support on app, mobile web or web (Dynamic QR). When the Customer chooses the UPI app on the payment page and clicks the Pay button, Merchant calls Juspay’s transaction API with parameters depending on different payment methods chosen by the Customer. The API response will have the parameters required for constructing the intent URI. Merchant can then construct the URI and invoke the APP using chrome intent feature.

Construction of UPI Pay String code through the string mentioned
The sdk_params obtained in the response of the UPI transaction call should be used for constructing the Intent URI.

**_Sample URI:
upi://pay?tr=202101345671229366&tid=121313202101345671229366&pa=example@axisbank&mc=1234&pn= Merchant%20Inc&am=1.00&cu=INR&tn=Pay%20for%20merchant_**

**Format:
upi://pay?tr=...(enter the tr).......&tid=...(enter the tid).......&pa=.....(enter merchant_vpa)...&mc=....(enter the mcc)...&pn=....(enter
the Merchant name)...&am=.....(enter the amount).....&cu=INR&tn=....(description for the transaction)..
**
Note
In the URI spaces are replaced by "%20". The URI is encoded. Kindly generate the intent URI dynamically ie, based on the params received in the sdk_params response. Do not hardcode any keys or values as it can differ with different PG’s.

How to create an intent from mWeb browser?
Once the URI is constructed, it should be embedded into the page. The mobile browser then checks for the UPI apps on the phone and displays them. Customer clicks on the app and completes the payment.

_Sample Reference for chrome Intent is given below:
https://developer.chrome.com/multidevice/android/intents
_
How to create a dynamic QR on Web?
From the response parameters of the transaction API call for QR Code payment method, the SDK parameters are can be used to construct a URI and bind that URI to QR code.

**Generating UPI Pay String and binding it with QR code :
There are several Js libraries that help in generating QR code and binding string with the QR code. Sample library : https://www.npmjs.com/package/qrcode
**
Merchant needs to bind the Pay String using the following steps:
1)Create QR code object
2)Encode the UPI Pay String to bytes
3)Make QR code

How to handle payment status once the payment is completed?
Unlike in Web collect, where the success response is redirected to the merchant's return url as well as through server callback, in intent, only a callback response is posted on Merchant’s server. This is because UPI intent is an App to app switch push payment. While payment is being done via the UPI app, Merchant has to show a waiting/loader page on the background. Merchants should continuously poll their own server to check for Kolkata Fatafat callback of payment status and give the response in the frontend to the client side. Merchant can also call the order status API of Kolkata FF to check the Order Status of the transaction.

We can use anchor tags to invoke UPI apps (GPay, PhonePay, PayTm, BHIMPay, AmazonPay or any UPI Apps).
For example -

https://kolkataff.win/upi-getway/

**1. Add the schema of the apps into Info.plist **
LSApplicationQueriesSchemes(Array).

 



 

**2. Add the following lines where your web view loads.**

 

copy icon
webConfiguration.userContentController = WKUserContentController( )
webConfiguration.userContentController.add(self, name: "sendSignalToNative")
 

**3. Conform to protocol WKScriptMessageHandler and define the following variables in your Webview controller:**

copy icon
var txnToken: String = " "
var pspAppsAvailableInDevice : [PspSchema] = [ ]
 

**4. Implement the required function of the protocol.
**
 

copy icon
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        let data = message.body as? [String : Any]
        if let json = data,  let message = json["message"] as? String {
            if let tokenData = json["tokenData"] as? [String : Any], let token = tokenData["token"] as? String{
                txnToken = token
            }
            if message == Signal.callPSPApp.rawValue {
                setPSP( )
            } else if message == Signal.invokePSPApp.rawValue, let deeplink = json["deeplink"] as? String {
                invokeIntentApps(urlString: deeplink)
            }
        }
 }
 

**5. Make a model to parse data from the API.
**
 

copy icon
enum Signal : String {
    case callPSPApp = "Execute setUpiIntentApps"
    case invokePSPApp = "Invoke PSP app"
}

struct APIResponse : Decodable {
    let body: Body
}

struct Body : Decodable {
    let pspSchemas: [PspSchema]?
}

struct PspSchema: Decodable {
    let displayName, name, icon, scheme: String
}
 

**6. Now add the following helper methods.
**
 [Kolkata Fatafat][1]

i) To convert the array to the dictionary, use below code snippet.

copy icon
 func arrayToDict(apps: [PspSchema]) -> [[String:Any]] {
        var dict = [[String:String]]()
        for app in apps {
            var localDict : [String:String] = [ : ]
            localDict["displayName"] = app.displayName
            localDict["icon"] = app.icon
            localDict["name"] = app.name
            localDict["scheme"] = app.scheme
            dict.append(localDict)
        }
        return dict
    }
 

**ii) Check which apps are installed on the user’s device.**

copy icon
 func checkAppsInDevice( psps: [PspSchema] ) {
   pspAppsAvailableInDevice = [ ]
      for app in psps {
         let fullScheme = app.scheme + "://"
         if let url = URL(string: fullScheme), UIApplication.shared.canOpenURL(url) {
            self.pspAppsAvailableInDevice.append(app)
         }
      }
 }
 

**iii) Convert the array of installed app names to JSON and send it to our web team to show intent.**

 

copy icon
 func convertIntoJSONString(arrayObject: [Any]) -> String {
      do {
            let jsonData: Data = try JSONSerialization.data(withJSONObject: arrayObject, options: [ ] )
            if  let jsonString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue){
                return jsonString as String
            }
      } catch let error as NSError {
            debugPrint("Array convertIntoJSON - \(error.description)")
      }
      return ""
 }

 func setPSP( ) {
    fetchPspApps { [unowned self] PSPScheme, message, status in
       self.checkAppsInDevice(psps: PSPScheme)
       let dataToSent = self.convertIntoJSONString(arrayObject: self.arrayToDict(apps: self.pspAppsAvailableInDevice))
       DispatchQueue.main.async {
         self.webView.evaluateJavaScript("window.upiIntent.setUpiIntentApps('\(String(describing: dataToSent))');" )
       }
    }
 }

 

**iv) Make the API call**

copy icon

    func fetchPspApps(completionHandler: @escaping (([PspSchema], String, Bool) -> Void)) {
        executeRequest(urlString: "https://securegw.paytm.in/theia/api/v1/fetchPspApps", httpMethod: "POST") { PSPScheme,_, status in
            completionHandler(pspScheme, "", status)
        }
    }
               
    func executeRequest(urlString: String, httpMethod:String, completionHandler: @escaping (([PspSchema], String, Bool) -> Void) ) {
        do {
            let url = URL(string: urlString)
            guard let requestUrl = url else { return }
            var request = URLRequest(url: requestUrl)
            request.httpMethod = httpMethod
            let bodyParams = [
                "head": [
                    "tokenType":"TXN_TOKEN",
                    "txnToken": txnToken
                ],
                "body": [ : ]
            ] as [String : Any]
            
            do {
                let data = try JSONSerialization.data(withJSONObject: bodyParams, options: .prettyPrinted)
                request.httpBody = data
            } catch{
                print("🔴", error)  // Handle accordingly
            }
            request.httpMethod = "POST"
            request.addValue("application/json", forHTTPHeaderField: "Content-Type")
            
            let task = URLSession.shared.dataTask(with: request) {(data,response,error) in
                
                guard error == nil else {
                    print(error!.localizedDescription) // Handle accordingly
                    completionHandler([ ], "", false)
                    return
                }
                guard data != nil else {
                    completionHandler([ ], "", false)
                    return
                }
                do {
                    let json = try JSONDecoder().decode(APIResponse.self, from: data!)
                    if let schemas = json.body.pspSchemas, !schemas.isEmpty {
                        completionHandler(schemas, "", true)
                    }else{
                        completionHandler( [ ], "", false)
                    }
                } catch {
                    completionHandler( [ ], "", false)
                }
            }
            task.resume( )
        }
    }
 


[Kolkata Fatafat](https://kolkataff.win)