58

I need to integrate a new payment gateway to our corporate website, which is based on Social Engine. There is an extension for this CMS called Advanced Payment Gateways which allows integration of new gateways. In fact, it gets your gateway name and generates a skeleton structure zipped as a file so you can unzip and upload to your server and thus merge with the application directory.

I'm going to explain how I implement my gateway without Social Engine, and I hope someone can tell me how I can incorporate that into Social Engine.

  1. First I connect to my PSP service:

    $client = new nusoap_client('https://example.com/pgwchannel/services/pgw?wsdl');
    
  2. I prepare the following parameters in an array to send to bpPayRequest:

    $parameters = array(
        'terminalId' => $terminalId,
        'userName' => $userName,
        'userPassword' => $userPassword,
        'orderId' => $orderId,
        'amount' => $amount,
        'localDate' => $localDate,
        'localTime' => $localTime,
        'additionalData' => $additionalData,
        'callBackUrl' => $callBackUrl,
        'payerId' => $payerId);
    
    // Call the SOAP method
    $result = $client->call('bpPayRequest', $parameters, $namespace);
    
  3. If payment request is accepted, the result is a comma separated string, with the first element being 0.
    Then we can send the second element (reference id) to payment gateway as follows via POST method:

    echo "<script language='javascript' type='text/javascript'>postRefId('" . $res[1] . "');</script>";
    
    <script language="javascript" type="text/javascript">    
        function postRefId (refIdValue) {
            var form = document.createElement("form");
            form.setAttribute("method", "POST");
            form.setAttribute("action", "https://example.com/pgwchannel/startpay");         
            form.setAttribute("target", "_self");
            var hiddenField = document.createElement("input");              
            hiddenField.setAttribute("name", "RefId");
            hiddenField.setAttribute("value", refIdValue);
            form.appendChild(hiddenField);
    
            document.body.appendChild(form);         
            form.submit();
            document.body.removeChild(form);
        }
        </script>
    
  4. The gateway will return the following parameters via POST method to the call back URL that we provided in payment request:
    RefId (reference id as produced in previous steps)
    ResCode (Result of payment: 0 denotes success)
    saleOrderId (order id as passed during payment request)
    SaleReferenceId (sale reference code is given by PSP to the merchant)

  5. If ResCode in the previous step was 0, then we'd need to pass the call bpVerifyRequest with the following parameters to verify payment, otherwise the payment will be canceled.

     $parameters = array(
        'terminalId' => $terminalId,
        'userName' => $userName,
        'userPassword' => $userPassword,
        'orderId' => $orderId,
        'saleOrderId' => $verifySaleOrderId,
        'saleReferenceId' => $verifySaleReferenceId);
    
    // Call the SOAP method
    $result = $client->call('bpVerifyRequest', $parameters, $namespace);
    
  6. In case the result of bpVerifyRequest is zero, payment is certain and the merchant has to provide goods or services purchased. However, there is an optional method bpSettleRequest, which is used to request a settlement. It is called as follows:

    $parameters = array(
        'terminalId' => $terminalId,
        'userName' => $userName,
        'userPassword' => $userPassword,
        'orderId' => $orderId,
        'saleOrderId' => $settleSaleOrderId,
        'saleReferenceId' => $settleSaleReferenceId);

    // Call the SOAP method
    $result = $client->call('bpSettleRequest', $parameters, $namespace);

I get confused by looking at default gateways in the Payment Gateways plugin e.g. PayPal, Stripe, 2Checkout, etc. How am I incorporate this code logic into the newly created gateway skeleton? (the structure is shown below):
enter image description here

You can check out the complete source code here:
default.php
callback.php

Mehdi Haghgoo
  • 3,144
  • 7
  • 46
  • 91
  • Are the values you want (pay amount and order id) stored in input fields? – Script47 Sep 04 '17 at 10:59
  • @Script47 yes. Let's say a user adds a product to cart and then proceeds to payment. That is where I want to use the code. – Mehdi Haghgoo Sep 04 '17 at 11:31
  • @Could you not just store that data temporarily somewhere? – Script47 Sep 04 '17 at 11:54
  • @Script47 that's not the problem. I need to send order id and amount among other things to the gateway, but I do not know how to access them. – Mehdi Haghgoo Sep 04 '17 at 12:02
  • @Script47 Do you need the diagram or the codes? – Prince Adeyemi Sep 07 '17 at 00:34
  • @LasVegasCoder I don't need anything, what do you mean? – Script47 Sep 07 '17 at 07:51
  • Regardless of weather this is worded like a code question or not, it does not take away from the fact a programmer should be getting paid to write this implementation for you. Adding a large bounty on it suggests that you know this but are not prepared to compensate someone with the appropriate experience properly. Please consider removing this question, and contact a free-lancer network to get a quote for the job. – Kodaloid Sep 10 '17 at 13:37
  • @Kodaloid I appreciate your take, but the fact is that the plugin vendors have said in their document that we can easily integrate our own gateway by following the procedure they laid out. I have done that and there is apparently a small coding task to be done. I managed to write my code in Engine_Payment_Gateway_Mygateway class and now it is working, but it loads only on Desktop view of the site (not in mobile mode). – Mehdi Haghgoo Sep 10 '17 at 16:47
  • 2
    That then is a different question to "How to add a custom payment gateway to Social Engine" re-enforcing my argument. If you only have an issue with the gateway not working on mobile then please re-word the question so that that is the only thing you are asking. I ask this just in-case a budding programmer accidentally wastes a lot of time giving you an implementation of a gateway for social engine which most of the time in the industry would be a paid for job. By putting such a high bounty on it, it comes off as a bribe, and for someone to take that would be to diminish their worth. – Kodaloid Sep 10 '17 at 17:11
  • @Kodaloid this never occurred to me as a bribe. It was only because of the importance of the matter to me that i set as much as i could for bounty. My employer had set me to the job and would not be willing to outsource the job. – Mehdi Haghgoo Sep 10 '17 at 17:24
  • 2
    So you get paid when someone helps you for free, their only reward is points on a website. I don't think I need to make my point any clearer. – Kodaloid Sep 10 '17 at 17:31
  • your question is,how use this gateway in android or ios?? – nima Sep 11 '17 at 07:28
  • Which PHP framework it is which is referenced here? – Murtaza Khursheed Hussain Sep 11 '17 at 07:28
  • @MurtazaKhursheedHussain it is Zend. – Mehdi Haghgoo Sep 11 '17 at 08:32
  • 1
    Why does it fail on mobile? If there is no error we cannot help – Deckerz Sep 11 '17 at 08:32
  • @Deckerz Unfortunately there is no error. error_log is empty. In fact it shows order success message 'Thanks for your order, you'll soon receive order invoice...', instead of calling `processTransaction` from `class Engine_Payment_Gateway_Behpardakht`. I wish there was a way I could track the browser which resources are being used when on this page. – Mehdi Haghgoo Sep 11 '17 at 08:38
  • 1
    @JasonStack try logging with `error_log` at each point in the code and see if it is skipping any of it. Log at every point. – Deckerz Sep 11 '17 at 08:39
  • @Deckerz thanks. error_log shows that when on mobile mode, neither of those logs are printed, but in Desktop view they are. – Mehdi Haghgoo Sep 11 '17 at 10:09
  • that is mellat gateway, and it is quite simple i cant undestand what is your problem!! – nima Sep 11 '17 at 10:18
  • you cant check `error_log` because if all error happen in bank gateway – nima Sep 11 '17 at 10:20
  • @nima that's Social Engine that makes the thing a bit difficult. It works on Desktop view however, and all evil comes with mobile view. It seems mobile view does not call Engine_Payment_Gateway_Mygateway at all!, since error_log does not record anything when making mobile payments. – Mehdi Haghgoo Sep 11 '17 at 10:27
  • does your js file load gateway page,the page you can pay your amount – nima Sep 11 '17 at 10:48
  • @nima yes normally, a piece of javascript code in the mentioned class loads the gateway. But, in mobile mode the whole file does not seem to be executed in the first place. – Mehdi Haghgoo Sep 11 '17 at 10:52
  • your gateway doesn't load in mobile browser(chrome,firefox, ... ) or in application mobile that quite diffrent – nima Sep 11 '17 at 10:56
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154131/discussion-between-jasonstack-and-nima). – Mehdi Haghgoo Sep 11 '17 at 10:57
  • Have you thought of Basic Attention Tokens (BAT) and the brave browser? – user50619 Oct 08 '18 at 08:30
  • @OliverTappin not anymore! – Mehdi Haghgoo Oct 08 '18 at 09:16

1 Answers1

2

I solved this by adding the payment code inside the Engine_Payment_Gateway_MyGateway class:

Once the user confirms on the SocialEngine page that they want to pay, the method processTransaction() inside the mentioned class is called and the user is redirected to the PSP's payment secure page. Once they are done with the payment, i.e. paid successfully or failed or canceled the transaction, they PSP's page redirects them to the page we had sent to it earlier as a parameter called callBackUrl. There, you will receive PSP-specific parameters which helps you decide whether the payment was successful and to ask the PSP with another SOAP call to confirm the payment and then optionally ask it to settle (deposit money ASAP into the seller's account):

Add to processTransaction():

        $data = array();
        $rawData = $transaction->getRawData();

        //Save order ID for later
        $this->_orderId = $rawData['vendor_order_id'];
        $this->_grandTotal = $rawData['AMT'];


        $client = new nusoap_client('https://example.com/pgwchannel/services/pgw?wsdl');
        $namespace = 'http://interfaces.core.sw.example.com/';


        // Check for an error
        $err = $client->getError();
        if ($err) {
            echo '<h2>Constructor error</h2><pre>' . $err . '</pre>';
            die();
        }


        /* Set variables */

//Get price from SEAO 
//$order_ids = Engine_Api::_()->getDbTable('orders','sitestoreproduct')->getOrderIds($this->parent_id);
//$price = Engine_Api::_()->getDbTable('orders','sitestoreproduct')->getGrandTotal($this->parent_id);


        $terminalId = '1111111';
        $userName = 'username';
        $userPassword = '1111111';
        $orderId = $rawData['vendor_order_id'];

        $amount = $rawData['AMT'];
        $localDate = date("Y") . date("m") . date("d");
        $localTime = date("h") . date("i") . date("s");
        $additionalData = $rawData['return_url'];
        $callBackUrl = 'https://example.com/pgateway/pay/callback';
        $payerId = '0';







        /* Define parameters array   */

        $parameters = array(
            'terminalId' => $terminalId,
            'userName' => $userName,
            'userPassword' => $userPassword,
            'orderId' => $orderId,
            'amount' => $amount,
            'localDate' => $localDate,
            'localTime' => $localTime,
            'additionalData' => $additionalData,
            'callBackUrl' => $callBackUrl,
            'payerId' => $payerId
        );



        $result = $client->call('bpPayRequest', $parameters, $namespace);



        if ($client->fault) {
            echo '<h2>Fault</h2><pre>';
            print_r($result);
            echo '</pre>';
            die();
        } else { //Check for errors
            $error = $client->getError();
            if ($error) {
                echo "An error occurred: ";
                print_r($error);
                die();
            } else {
                //break the code
                $resultSegmts = explode(',', $result);
                $ResCode = $resultSegmts [0];


                if ($ResCode == "0") {
                    //Notify admin of the order                    
                    echo '<h3>Redirecting you to the payment page. Please wait...</h3><br/>';
                    echo '<script language="javascript" type="text/javascript">
                      postRefId("' . $resultSegmts[1] . '");
                    </script>';
                } elseif ($ResCode == "25") {
                    echo "<h3>Purchase successful</h3>";
                } else {
                    echo "<h3>PSP response is: $ResCode</h3>";
                } 
            }
        }

Add to your callBack action:

    $this->view->message = 'This is callback action for PayController';
    $RefId = $_POST['RefId'];
    $ResCode = $_POST['ResCode'];
    $saleOrderId = $_POST['SaleOrderId'];
    $saleReferenceId = $_POST['SaleReferenceId'];

    $this->_orderId = $saleOrderId;

        $this->view->RefId = $RefId;
        $this->view->saleOlderId = $saleOrderId;
        $this->view->saleReferenceId = $saleReferenceId;
    }
    if ($ResCode == "0") {
        try {
            $client = new nusoap_client('https://example.com/pgwchannel/services/pgw?wsdl');
        } catch (Exception $e) {
            die($e->getMessage());
        }

        $namespace = 'http://interfaces.core.sw.example.com/';
        $terminalId = "111111";
        $userName = "username";
        $userPassword = "11111111";


        $parameters = array(
            'terminalId' => $terminalId,
            'userName' => $userName,
            'userPassword' => $userPassword,
            'orderId' => $saleOrderId,
            'saleOrderId' => $saleOrderId,
            'saleReferenceId' => $saleReferenceId
        );
        $resVerify = $client->call('bpVerifyRequest', $parameters, $namespace);



        if ($resVerify->fault) { //Check for fault 
            echo "<h1>Fault: </h1>";
            print_r($result);
            die();
        } else { //No fault: check for errors now 
            $err = $client->getError();
            if ($err) {
                echo "<h1>Error: " . $err . " </h1>";
            } else {
                if ($resVerify == "0") {//Check verification response: if 0, then purchase was successful. 
                    echo "<div class='center content green'>Payment successful. Thank you for your order.</div>";
                    $this->view->message = $this->_translate('Thanks for your purchase.');
                    $this->dbSave(); //update database table
                } else
                    echo "<script language='javascript' type='text/javascript'>alert(    'Verification Response: " . $resVerify . "');</script>";
            }
        }

        //Note that we need to send bpSettleRequest to PSP service to request settlement once we have verified the payment 
        if ($resVerify == "0") {
            // Update table, Save RefId
            //Create parameters array for settle
            $this->sendEmail();
            $this->sendSms();

            $resSettle = $client->call('bpSettleRequest', $parameters, $namespace);
            //Check for fault 
            if ($resSettle->fault) {
                echo "<h1>Fault: </h1><br/><pre>";
                print_r($resSettle);
                echo "</pre>";
                die();
            } else { //No fault in bpSettleRequest result 
                $err = $client->getError();
                if ($err) {
                    echo "<h1>Error: </h1><pre>" . $err . "</pre>";
                    die();
                } else {
                    if ($resSettle == "0" || $resSettle == "45") {//Settle request successful 
                        // echo "<script language='javascript' type='text/javascript'>alert('Payment successful');</script>";
                    }
                }
            }
        }
    } else {
        echo "<div class='center content error'>Payment failed. Please try again later.</div> ";
        // log error in app
        // Update table, log the error
        // Show proper message to user
    }
    $returnUrl = 'https://example.com/stores/products'; //Go to store home for now. Later I'll set this to the last page 
    echo "<div class='center'>";
    echo "<form action=$returnUrl method='POST'>";
    echo "<input class='center' id='returnstore' type='submit' value='Return to store'/>";
    echo "</form>";
    echo "</div>";
Mehdi Haghgoo
  • 3,144
  • 7
  • 46
  • 91