Welcome to MonJoomla forum board.

New Payment Methods

New Payment Methods

Hi Lebill,

I need to set up a new payment method using PayFast (A South African based payment gateway). I have never used PayPal before and didn't realise that although they offer services to South Africa, they do not offer our currency (ZAR). This is a massive problem for us now as we cannot offer gift cards in our currency, and that does not look very good for customers who wish to purchase on the site. This means that unless we can build a new payment gateway into the system, this extension will not be useful to us or any other South African companies.

I did read in another thread that it is possible, and I have located the file that contains the code in question (checkout.php).
PayFast has a custom integration guideline and all their sample PHP code on their website, but I need to know where to include this in your system and what files to edit, if it is possible?

Thanks

Kayne
useravatar
Offline
9 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Hello

Yes it's possible, and you found the right file (checkout.php)

In it you have the function to validate the payment and the function to start the card creation.

Normally if you want to add a new payment you just need to change the way I validate the payment.

at line 295 in checkout.php you have this

Code:

function validate() {

you remove my code and replace with the new way to validate the payment, this function return true or false.

Also you need to change the form (what is sent to paypal) for the payment.

Check in the file

/components/com_kocustomgiftcard/views/previz/tmpl/previz.php

At the end you have all the hidden fields ready to be sent to paypal, you need to replace some of them with the one you need for the new payment.

Now in the file most of the value are variables, best trick, go into this page  with your browser, (the page with the preview, just before paypal) and do a view source to see all the right value.

The last thing to do is changing where the form go, for that you need to edit the js file

/components/com_kocustomgiftcard/assets/js/ko_cgc.js

at line 53 you have this

Code:

document.ko_cgc.action = "https://www.paypal.com/cgi-bin/webscr";

just change it for the url of your new payment method.

Normally that's it

Let me know

Thanks

Thanks for your support

If you like my Joomla apps, please help support them with a review here:
http://extensions.joomla.org/

Thank you!

lebill
useravatar
Offline
1699 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Hi Lebill,

I have managed to change the payment function and I have tested it and the payment process is working fine. Could you help me identify what to change in order to update the database? this is the only thing I am struggling with.

This is what my checkout.php looks like now:

Code:


    function validate() {
        // Variable initialization
        $pfError = false;
        $pfErrMsg = '';
        $filename = 'notify.txt'; // DEBUG
        $output = ''; // DEBUG
        $pfParamString = '';
        $pfHost = ( PAYFAST_SERVER == 'LIVE' ) ?
            'www.payfast.co.za' : 'sandbox.payfast.co.za';

       
// General defines
define( 'PAYFAST_SERVER', 'TEST' );
    // Whether to use "sandbox" test server or live server
define( 'USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)' );
    // User Agent for cURL

// Messages
    // Error
define( 'PF_ERR_AMOUNT_MISMATCH', 'Amount mismatch' );
define( 'PF_ERR_BAD_SOURCE_IP', 'Bad source IP address' );
define( 'PF_ERR_CONNECT_FAILED', 'Failed to connect to PayFast' );
define( 'PF_ERR_BAD_ACCESS', 'Bad access of page' );
define( 'PF_ERR_INVALID_SIGNATURE', 'Security signature mismatch' );
define( 'PF_ERR_CURL_ERROR', 'An error occurred executing cURL' );
define( 'PF_ERR_INVALID_DATA', 'The data received is invalid' );
define( 'PF_ERR_UKNOWN', 'Unknown error occurred' );

    // General
define( 'PF_MSG_OK', 'Payment was successful' );
define( 'PF_MSG_FAILED', 'Payment has failed' );


// Notify PayFast that information has been received
header( 'HTTP/1.0 200 OK' );
flush();


//// Dump the submitted variables and calculate security signature
if( !$pfError )
{
    $output = "Posted Variables:\n\n"; // DEBUG

    // Strip any slashes in data
    foreach( $_POST as $key => $val )
        $pfData[$key] = stripslashes( $val );

    // Dump the submitted variables and calculate security signature
    foreach( $pfData as $key => $val )
    {
        if( $key != 'signature' )
            $pfParamString .= $key .'='. urlencode( $val ) .'&';
    }

    // Remove the last '&' from the parameter string
    $pfParamString = substr( $pfParamString, 0, -1 );
    $signature = md5( $pfParamString );

    $result = ( $_POST['signature'] == $signature );

    $output .= "Security Signature:\n\n"; // DEBUG
    $output .= "- posted     = ". $_POST['signature'] ."\n"; // DEBUG
    $output .= "- calculated = ". $signature ."\n"; // DEBUG
    $output .= "- result     = ". ( $result ? 'SUCCESS' : 'FAILURE' ) ."\n"; // DEBUG
}

//// Verify source IP
if( !$pfError )
{
    $validHosts = array(
        'www.payfast.co.za',
        'sandbox.payfast.co.za',
        'w1w.payfast.co.za',
        'w2w.payfast.co.za',
        );

    $validIps = array();

    foreach( $validHosts as $pfHostname )
    {
        $ips = gethostbynamel( $pfHostname );

        if( $ips !== false )
            $validIps = array_merge( $validIps, $ips );
    }

    // Remove duplicates
    $validIps = array_unique( $validIps );

    if( !in_array( $_SERVER['REMOTE_ADDR'], $validIps ) )
    {
        $pfError = true;
        $pfErrMsg = PF_ERR_BAD_SOURCE_IP;
    }
}

//// Connect to server to validate data received
if( !$pfError )
{
    // Use cURL (If it's available)
    if( function_exists( 'curl_init' ) )
    {
        $output .= "\n\nUsing cURL\n\n"; // DEBUG

        // Create default cURL object
        $ch = curl_init();

        // Base settings
        $curlOpts = array(
            // Base options
            CURLOPT_USERAGENT => USER_AGENT, // Set user agent
            CURLOPT_RETURNTRANSFER => true,  // Return output as string rather than outputting it
            CURLOPT_HEADER => false,         // Don't include header in output
            CURLOPT_SSL_VERIFYHOST => true,
            CURLOPT_SSL_VERIFYPEER => false,

            // Standard settings
            CURLOPT_URL => 'https://'. $pfHost . '/eng/query/validate',
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $pfParamString,
        );
        curl_setopt_array( $ch, $curlOpts );

        // Execute CURL
        $res = curl_exec( $ch );
        curl_close( $ch );

        if( $res === false )
        {
            $pfError = true;
            $pfErrMsg = PF_ERR_CURL_ERROR;
        }
    }
    // Use fsockopen
    else
    {
        $output .= "\n\nUsing fsockopen\n\n"; // DEBUG

        // Construct Header
        $header = "POST /eng/query/validate HTTP/1.0\r\n";
           $header .= "Host: ". $pfHost ."\r\n";
        $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
        $header .= "Content-Length: " . strlen( $pfParamString ) . "\r\n\r\n";

        // Connect to server
        $socket = fsockopen( 'ssl://'. $pfHost, 443, $errno, $errstr, 10 );

        // Send command to server
        fputs( $socket, $header . $pfParamString );

        // Read the response from the server
        $res = '';
        $headerDone = false;

        while( !feof( $socket ) )
        {
            $line = fgets( $socket, 1024 );

            // Check if we are finished reading the header yet
            if( strcmp( $line, "\r\n" ) == 0 )
            {
                // read the header
                $headerDone = true;
            }
            // If header has been processed
            else if( $headerDone )
            {
                // Read the main response
                $res .= $line;
            }
        }
    }
}

//// Get data from server
if( !$pfError )
{
    // Parse the returned data
    $lines = explode( "\n", $res );

    $output .= "\n\nValidate response from server:\n\n"; // DEBUG

    foreach( $lines as $line ) // DEBUG
        $output .= $line ."\n"; // DEBUG
}

//// Interpret the response from server
if( !$pfError )
{
    // Get the response from PayFast (VALID or INVALID)
    $result = trim( $lines[0] );

    $output .= "\nResult = ". $result; // DEBUG

    // If the transaction was valid
    if( strcmp( $result, 'VALID' ) == 0 )
    {
        // Process as required
    }
    // If the transaction was NOT valid
    else
    {
        // Log for investigation
        $pfError = true;
        $pfErrMsg = PF_ERR_INVALID_DATA;
    }
}

// If an error occurred
if( $pfError )
{
    $output .= "\n\nAn error occurred!";
    $output .= "\nError = ". $pfErrMsg;
}

//// Write output to file // DEBUG
file_put_contents( $filename, $output ); // DEBUG

        if ( $this->_data["payment_status"] == "Completed") {         
                return true;       
         } else {     
              if ( $this->_data["payment_status"] == "Pending") {
                 $sql = "UPDATE #__ko_cgc  SET  barcode = '".$this->_data["payment_status"]."', transaction_id = '".$this->_data["pending_reason"]."', payment_date = '".date('Y-m-d H:i:s')."' WHERE id like '".$this->_data['custom']."';";           
                $this->_db->setQuery($sql) ;
                $this->_db->Query() ;
             }
                     
             return false;
         }   
    }

Kayne
useravatar
Offline
9 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Wow

Great work, the next step is to match some variable in the next function paypalConfirm (in the same file, checkout.php)

Just after you validate your payment (line 49), you need to match those 4 variables at the top

$this->_data['custom']  /// The master key MD5
$this->_data['txn_id']  /// Transaction ID
$this->_data['mc_gross']  /// Amount of the transaction
$this->_data['discount']   /// the amount of discount (if you have one)

When those variable are full, the rest of the code should work fine.

Thanks

Thanks for your support

If you like my Joomla apps, please help support them with a review here:
http://extensions.joomla.org/

Thank you!

lebill
useravatar
Offline
1699 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Hi Lebill!

I matched the changed the variables in the checkout.php @line 42 to the variables being passed back from PayFast, but the database is still not updating. Are there any other files that reference the variables @line42?

this is what I have put there:

Code:


$this->_id = $this->_data['custom_str1'];                       
               $transactionId = $this->_data['pf_payment_id'];
               $amount = $this->_data['amount_gross'];
                  if($this->_data['discount'] != "") { $amount = $amount + $this->_data['discount']; }

I also changed the statement to include my new payment method result:

Code:


if( strcmp( $result, 'VALID' ) == 0 ) { return false ; }
               if ($amount < 0) { return false ; }
               $sql = "UPDATE #__ko_cgc  SET  barcode = '".$barNumber."', card_balance='".$this->_data['amount_gross']."', card_total='".$amount."', active=1, transaction_id = '".$transactionId."', payment_date = '".date('Y-m-d H:i:s')."' WHERE id like '".$this->_id."';";           
            $this->_db->setQuery($sql) ;
            $this->_db->Query() ;

I am receiving an email to my Admin address afrter I process the payment, but it is missing the md5 in the link, and opens a blank page:
index.php?option=com_kocustomgiftcard&tmpl=component&task=print_card&md5=

Kayne
useravatar
Offline
9 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Ahhhh

This is your problem the missing MD5, for the update in the database and the bad email.

The best start from the start, check in the html, the hidden fields, (do a view code) check if the fields have the md5 in it. If yes, check the second step, when you validate the payment, check if the payment company return you the md5, if Yes, be sure you set it to the variable.

Also check in the database if you have the md5, this is save with AJAX, just before going to the payment interface. In the .js file (javascript) at the end you have the function to send the ajax and when the ajax is ok the javascript POST the form.

You are very close, normally with the md5 everything will work fine.

Let me know

Thanks for your support

If you like my Joomla apps, please help support them with a review here:
http://extensions.joomla.org/

Thank you!

lebill
useravatar
Offline
1699 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Yeah I eventually came to that conclusion. I have worked out that PayFast is not posting the details to the 'notify_url'. I confirmed this by placing a dummy 'notify_url' that would return 403 error, but it still processes the order. I will have to contact there support department to figure out what is going on there. Also I looked at the ipnLogs.txt file and saw that my tests with PayPAL and PayFAST had been posting back data until 16/09/2013 (Moday), but there are no further records in that file despite numerous tests this week.

One thing I did notice though is that the md5 key's are all different values. In the  "Preview" cards window, when I 'view source' it shows one number, then when I click 'buy now' and check the database entry, the number under "id" is different. Is this normal?

Thanks for your help so far! It is much appreciated.

I will keep you posted as to my progress.

Cheers..

Kayne
useravatar
Offline
9 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Hello

With Paypal we have a switch to turn on to tell paypal to send IPN, maybe it's the same with Payfast.

For the MD5, it cannot be different it's the key, in the form you sent to the payment thing, you have the custom hidden field, if this md5 is different to the one insert in the database, we have a problem.

Be sure the ID key of the entry in the database match the one sent to the payment processor (custom hidden field). In my book it's impossible they are different.

Let me know

Thanks for your support

If you like my Joomla apps, please help support them with a review here:
http://extensions.joomla.org/

Thank you!

lebill
useravatar
Offline
1699 Posts
User info in posts
Administrator has disabled public posting

Re: New Payment Methods

Hi Lebill,

Just an update, I managed to get it working. The problem was that I had not specified "_data" in my new payment method, so the variables from PayFast where not being passed on by

Code:

function validate() {

to

Code:

function paypalConfirm() {

.

What I did was add

Code:

$this->_data = $pfData;

to my new payment method ($pfData is the variable that contains the data posted back by PayFast).

PayFast doesn't use a switch for the ITN, your just need to specify the 'notify_url' variable. And with regards to the md5, I worked out that when you create your card in the constructor, and click 'Preview' it generates an md5, and when you click 'Buy Now' it generates a different md5, and that is the one that is added to the database and sent in the form. I was opening "CodeView" in the 'Preview' window and comparing the md5 in the values there to the one posted in the database (silly me!).

Thanks again for your help! Hopefully this will help someone else in the future.

Now I have to do this for another plugin... neutral

Cheers!

Kayne
useravatar
Offline
9 Posts
User info in posts
Administrator has disabled public posting

Board Info

Board Stats:
 
Total Topics:
818
Total Polls:
0
Total Posts:
167772680
Dormant:
User Info:
 
Total Users:
4338
Newest User:
golato
Members Online:
0
Guests Online:
339

Online: 
There are no members online

Forum Legend:

 Topic
 New
 Locked
 Sticky
 Active
 New/Active
 New/Locked
 New Sticky
 Locked/Active
 Active/Sticky
 Sticky/Locked
 Sticky/Active/Locked